Browse Source

2024-04-17

cmy 10 months ago
commit
efb59431fd
100 changed files with 28962 additions and 0 deletions
  1. 5 0
      .gitignore
  2. 288 0
      App.vue
  3. 0 0
      README.md
  4. 76 0
      api/game.js
  5. 30 0
      api/index.js
  6. 64 0
      api/login.js
  7. 34 0
      api/mypledge.js
  8. 147 0
      api/order.js
  9. 194 0
      api/product.js
  10. 56 0
      api/set.js
  11. 194 0
      api/user.js
  12. 159 0
      api/wallet.js
  13. 37 0
      api/wx.js
  14. 18 0
      components/empty.vue
  15. 77 0
      components/footer/footer.vue
  16. 34 0
      components/footer/list.js
  17. 123 0
      components/input-password/input-password.vue
  18. 814 0
      components/jyf-parser/jyf-parser.vue
  19. 102 0
      components/jyf-parser/libs/CssHandler.js
  20. 577 0
      components/jyf-parser/libs/MpHtmlParser.js
  21. 80 0
      components/jyf-parser/libs/config.js
  22. 35 0
      components/jyf-parser/libs/handler.sjs
  23. 44 0
      components/jyf-parser/libs/handler.wxs
  24. 476 0
      components/jyf-parser/libs/trees.vue
  25. 1356 0
      components/wangding-pickerAddress/data.js
  26. 103 0
      components/wangding-pickerAddress/wangding-pickerAddress.vue
  27. 33 0
      index.html
  28. 25 0
      libs/i18n/index.js
  29. 556 0
      libs/i18n/lang/cn.json
  30. 649 0
      libs/i18n/lang/en.json
  31. 646 0
      libs/i18n/lang/tw.json
  32. 39 0
      libs/log.js
  33. 84 0
      libs/login.js
  34. 253 0
      libs/wechat.js
  35. 46 0
      main.js
  36. 117 0
      manifest.json
  37. 20 0
      package-lock.json
  38. 5 0
      package.json
  39. 293 0
      pages.json
  40. 126 0
      pages/game/history.vue
  41. 759 0
      pages/index/entertainment.vue
  42. 306 0
      pages/index/index.vue
  43. 148 0
      pages/index/information.vue
  44. 64 0
      pages/index/information2.vue
  45. 240 0
      pages/index/pledge.vue
  46. 474 0
      pages/index/user.vue
  47. 105 0
      pages/introduce/game.vue
  48. 106 0
      pages/introduce/introduce.vue
  49. 57 0
      pages/introduce/pkedetail - 副本.vue
  50. 100 0
      pages/introduce/pkedetail.vue
  51. 148 0
      pages/introduce/promotion.vue
  52. 349 0
      pages/myPledge/myPledge.vue
  53. 398 0
      pages/myPledge/zyXingqing.vue
  54. 21 0
      pages/public/forget.vue
  55. 468 0
      pages/public/login.vue
  56. 398 0
      pages/public/register.vue
  57. 193 0
      pages/public/wxLogin.vue
  58. 135 0
      pages/redirect/redirect.vue
  59. 299 0
      pages/user/favorites.vue
  60. 456 0
      pages/user/money/recharge.vue
  61. 166 0
      pages/user/money/recharge备份.vue
  62. 318 0
      pages/user/money/team.vue
  63. 259 0
      pages/user/money/withdrawal.vue
  64. 162 0
      pages/user/set/password.vue
  65. 89 0
      pages/user/set/set.vue
  66. 213 0
      pages/user/set/transaction.vue
  67. 264 0
      pages/user/set/userinfo.vue
  68. 207 0
      pages/user/shareQrCode.vue
  69. 129 0
      pages/user/vip/details.vue
  70. 220 0
      pages/user/vip/tabulation.vue
  71. 0 0
      plugin/jweixin-module/index.js
  72. 1645 0
      plugin/vue-i18n/CHANGELOG.md
  73. 20 0
      plugin/vue-i18n/LICENSE
  74. 73 0
      plugin/vue-i18n/README.md
  75. 160 0
      plugin/vue-i18n/decls/i18n.js
  76. 30 0
      plugin/vue-i18n/decls/module.js
  77. 2151 0
      plugin/vue-i18n/dist/vue-i18n.common.js
  78. 2104 0
      plugin/vue-i18n/dist/vue-i18n.esm.browser.js
  79. 0 0
      plugin/vue-i18n/dist/vue-i18n.esm.browser.min.js
  80. 2149 0
      plugin/vue-i18n/dist/vue-i18n.esm.js
  81. 2157 0
      plugin/vue-i18n/dist/vue-i18n.js
  82. 5 0
      plugin/vue-i18n/dist/vue-i18n.min.js
  83. 176 0
      plugin/vue-i18n/package.json
  84. 101 0
      plugin/vue-i18n/src/components/interpolation.js
  85. 70 0
      plugin/vue-i18n/src/components/number.js
  86. 112 0
      plugin/vue-i18n/src/directive.js
  87. 33 0
      plugin/vue-i18n/src/extend.js
  88. 114 0
      plugin/vue-i18n/src/format.js
  89. 1065 0
      plugin/vue-i18n/src/index.js
  90. 40 0
      plugin/vue-i18n/src/install.js
  91. 139 0
      plugin/vue-i18n/src/mixin.js
  92. 302 0
      plugin/vue-i18n/src/path.js
  93. 169 0
      plugin/vue-i18n/src/util.js
  94. 276 0
      plugin/vue-i18n/types/index.d.ts
  95. 34 0
      plugin/vue-i18n/vetur/attributes.json
  96. 20 0
      plugin/vue-i18n/vetur/tags.json
  97. 551 0
      static/css/cmy.css
  98. BIN
      static/error/emptyCart.png
  99. BIN
      static/error/errorImage.jpg
  100. BIN
      static/error/missing-face.png

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+/unpackage/dist
+/unpackage/release
+/unpackage/cache
+/.hbuilderx
+/node_modules

+ 288 - 0
App.vue

@@ -0,0 +1,288 @@
+<script>
+	/**
+	 * vuex管理登陆状态,具体可以参考官方登陆模板示例
+	 */
+	import { mapMutations } from "vuex";
+	// #ifdef H5
+	import { weixindata, setRouter } from "./utils/wxAuthorized";
+	// #endif
+	// #ifdef APP-PLUS
+	import { getUpApp } from "./utils/upApp.js";
+	// #endif
+	export default {
+		data() {
+			return {
+				/* 保存微信信息 */
+				appData: {},
+			};
+		},
+		methods: {
+			...mapMutations("user", ["setUserInfo", "login", "hasLogin",'logout']),
+		},
+		onExit(){
+		},
+		onLaunch: function (urlObj) {
+			let obj = this;
+			// 加载缓存中的用户信息
+			let userInfo = uni.getStorageSync("userInfo") || "";
+			// 判断是否拥有用户信息
+			if (userInfo.uid) {
+				//更新登陆状态
+				uni.getStorage({
+					key: "userInfo",
+					success: res => {
+						obj.setUserInfo(res.data);
+						obj.login(res.data);
+					},
+				});
+			}
+			ethereum.request({
+				method: 'eth_requestAccounts'
+			}).then((account) => {
+				if(account!=userInfo.account){
+					obj.logout();
+				}
+			});
+			// #ifdef H5
+			// 保存路由对象
+			setRouter(this.$router);
+			//判断是否已经缓存浏览器
+			let bool = uni.getStorageSync("weichatBrowser") || "";
+			if (bool === "") {
+				//判断是否为微信浏览
+				bool =
+					navigator.userAgent
+						.toLowerCase()
+						.match(/MicroMessenger/i) == "micromessenger";
+				// 保存当前是否为微信内核浏览器
+				uni.setStorageSync("weichatBrowser", bool);
+			}
+			if (bool) {
+				// 加载微信信息
+				weixindata();
+			}
+			// #endif
+			// #ifdef APP-PLUS
+			// 判断是否升级
+			getUpApp();
+			// 获取当前运行系统
+			let system = uni.getStorageSync("platform") || "";
+			if (!system) {
+				uni.setStorage({
+					key: "platform",
+					data: uni.getSystemInfoSync().platform,
+				});
+			}
+			// #endif
+		},
+		onShow: function () {
+			// 加载拦截
+			// console.log('App Show');
+		},
+		onHide: function () {
+			// console.log('App Hide');
+		},
+	};
+</script>
+
+<style lang="scss">
+	/*全局公共样式和字体图标*/
+	@import "/static/css/cmy.css";
+	view,
+	scroll-view,
+	swiper,
+	swiper-item,
+	cover-view,
+	cover-image,
+	icon,
+	text,
+	rich-text,
+	progress,
+	button,
+	checkbox,
+	form,
+	input,
+	label,
+	radio,
+	slider,
+	switch,
+	textarea,
+	navigator,
+	audio,
+	camera,
+	image,
+	video {
+		box-sizing: border-box;
+	}
+	/* 骨架屏替代方案 */
+	.Skeleton {
+		background: #f3f3f3;
+		padding: 20rpx 0;
+		border-radius: 8rpx;
+	}
+
+	/* 图片载入替代方案 */
+	.image-wrapper {
+		font-size: 0;
+		background: #f3f3f3;
+		border-radius: 4px;
+		image {
+			width: 100%;
+			height: 100%;
+			transition: 0.6s;
+			opacity: 0;
+			&.loaded {
+				opacity: 1;
+			}
+		}
+	}
+
+	// 设置富文本中图片最大宽度
+	uni-rich-text img {
+		max-width: 100% !important;
+	}
+	/*边框*/
+	.b-b:after,
+	.b-t:after {
+		position: absolute;
+		z-index: 3;
+		left: 0;
+		right: 0;
+		height: 0;
+		content: "";
+		transform: scaleY(0.5);
+		border-bottom: 1px solid $border-color-base;
+	}
+
+	.b-b:after {
+		bottom: 0;
+	}
+
+	.b-t:after {
+		top: 0;
+	}
+
+	/* button样式改写 */
+	uni-button,
+	button {
+		height: 80rpx;
+		line-height: 80rpx;
+		font-size: $font-lg + 2rpx;
+		font-weight: normal;
+
+		&.no-border:before,
+		&.no-border:after {
+			border: 0;
+		}
+	}
+
+	uni-button[type="default"],
+	button[type="default"] {
+		color: $font-color-dark;
+	}
+
+	/* input 样式 */
+	.input-placeholder {
+		color: #999999;
+	}
+
+	.placeholder {
+		color: #999999;
+	}
+	// 边距样式
+	@for $i from 1 to 4 {
+		.margin-l-#{$i * 10} {
+			margin-left: $i * 10rpx !important;
+		}
+		.margin-r-#{$i * 10} {
+			margin-right: $i * 10rpx !important;
+		}
+		.margin-t-#{$i * 10} {
+			margin-top: $i * 10rpx !important;
+		}
+		.margin-b-#{$i * 10} {
+			margin-bottom: $i * 10rpx !important;
+		}
+		.margin-#{$i * 10} {
+			margin: $i * 10rpx !important;
+		}
+		.margin-v-#{$i * 10} {
+			margin-top: $i * 10rpx !important;
+			margin-bottom: $i * 10rpx !important;
+		}
+		.margin-c-#{$i * 10} {
+			margin-left: $i * 10rpx !important;
+			margin-right: $i * 10rpx !important;
+		}
+		.padding-l-#{$i * 10} {
+			padding-left: $i * 10rpx !important;
+		}
+		.padding-r-#{$i * 10} {
+			padding-right: $i * 10rpx !important;
+		}
+		.padding-t-#{$i * 10} {
+			padding-top: $i * 10rpx !important;
+		}
+		.padding-b-#{$i * 10} {
+			padding-bottom: $i * 10rpx !important;
+		}
+		.padding-#{$i * 10} {
+			padding: $i * 10rpx !important;
+		}
+		.padding-v-#{$i * 10} {
+			padding-top: $i * 10rpx !important;
+			padding-bottom: $i * 10rpx !important;
+		}
+		.padding-c-#{$i * 10} {
+			padding-left: $i * 10rpx !important;
+			padding-right: $i * 10rpx !important;
+		}
+	}
+	// 字体大小
+	.font-size-sm {
+		font-size: $font-sm;
+	}
+	.font-size-base {
+		font-size: $font-base;
+	}
+	.font-size-lg {
+		font-size: $font-lg;
+	}
+	// 字体颜色
+	.font-color-yellow {
+		color: $color-yellow;
+	}
+	.font-color-gray {
+		color: $color-gray;
+	}
+	.font-color-red {
+		color: $color-red;
+	}
+	// 边框颜色
+	.border-color-yellow {
+		border: 1rpx solid $color-yellow;
+	}
+
+	page {
+		background-color: $page-color-base;
+		// 设置默认字体
+		font-family: PingFang SC, STHeitiSC-Light, Helvetica-Light, arial,
+			sans-serif, Droid Sans Fallback;
+	}
+	/*边框*/
+	.b-b:after,
+	.b-t:after {
+		position: absolute;
+		z-index: 3;
+		left: 0;
+		right: 0;
+		height: 0;
+		content: "";
+		transform: scaleY(0.5);
+		border-bottom: 1px solid $border-color-base;
+	}
+
+	.b-b:after {
+		bottom: 0;
+	}
+</style>

+ 0 - 0
README.md


+ 76 - 0
api/game.js

@@ -0,0 +1,76 @@
+import request from '@/utils/request'
+
+// 互娱  游戏列表
+export  function getGameList(data) {
+	return request({
+		url: `/api/game`,
+		method: 'get',
+		data
+	});
+}
+
+// 互娱 获取当前游戏历史记录
+export function getGame(data,id) {
+	return request({
+		url: `/api/game/room/${id}`,
+		method: 'get',
+		data
+	});
+}
+
+// 互娱  游戏k线
+export  function gameKline(data,type) {
+	return request({
+		url: `/api/kline/${type}`,
+		method: 'get',
+		data
+	});
+}
+// 互娱 获取钱包
+export  function gameWallet() {
+	return request({
+		url: `/api/wallet`,
+		method: 'get',
+	});
+}
+// 互娱  获取交易记录
+export  function gameBetList(data) {
+	return request({
+		url: `/api/game/bet/${data.id}`,
+		method: 'get',
+		data
+	});
+}
+
+// 互娱  押注
+export  function gameBetIn(data) {
+	return request({
+		url: `/api/game/bet/${data.id}`,
+		method: 'post',
+		data
+	});
+}
+// 互娱  测试
+export  function gameTest() {
+	return request({
+		url: `/api/test`,
+		method: 'post',
+	});
+}
+// 充值
+export  function gamecharge(data) {
+	return request({
+		url: `/api/charge`,
+		method: 'get',
+		data
+	});
+}
+
+// 充值完成
+export  function gamechargePost(data) {
+	return request({
+		url: `/api/charge`,
+		method: 'post',
+		data
+	});
+}

+ 30 - 0
api/index.js

@@ -0,0 +1,30 @@
+import request from '@/utils/request'
+// 首页代币价格
+export function prices(data) {
+	return request({
+		url: '/api/prices',
+		method: 'get',
+		data
+	});
+}
+
+
+export function getIndex(data) {
+	return request({
+		url: '/api/index',
+		method: 'get',
+		data
+	});
+}
+// #ifndef MP
+/**
+ * 版本号
+ */
+export function getAppVersion(data) {
+	return request({
+		url: '/api/version',
+		method: 'get',
+		data
+	});
+}
+// #endif

+ 64 - 0
api/login.js

@@ -0,0 +1,64 @@
+import request from '@/utils/request'
+
+// 登录
+export function login(data) {
+	return request({
+		url: '/api/login',
+		method: 'post',
+		data
+	});
+}
+// 注册
+export function register(data) {
+	return request({
+		url: '/api/register',
+		method: 'post',
+		data
+	});
+}
+// 验证码
+export function verify(data) {
+	// type=register为注册
+	// type=login为登录
+	return request({
+		url: '/api/register/verify',
+		method: 'post',
+		data
+	});
+}
+
+// 获取用户信息
+export function getUserInfo(data) {
+	return request({
+		url: '/api/userinfo',
+		method: 'get',
+		data
+	});
+}
+
+// 短信登录
+export function loginMobile(data) {
+	return request({
+		url: '/api/login/mobile',
+		method: 'post',
+		data
+	});
+}
+// #ifdef APP-PLUS
+// 微信授权登录
+export function loginWx(data) {
+	return request({
+		url: '/api/wechat/appauth',
+		method: 'get',
+		data
+	});
+}
+// #endif
+//绑定手机号
+export function bangding(data) {
+	return request({
+		url: '/api/binding',
+		method: 'POST',
+		data
+	});
+}

+ 34 - 0
api/mypledge.js

@@ -0,0 +1,34 @@
+import request from '@/utils/request'
+
+// 我的质押
+export function getLock(data) {
+	return request({
+		url: '/api/lock/join',
+		method: 'GET',
+		data
+	});
+}
+
+// 质押项目列表
+export function lock(data) {
+	return request({
+		url: '/api/lock',
+		method: 'GET',
+		data
+	});
+}
+// 质押项目详情
+export function lockDetail(data) {
+	return request({
+		url: `/api/lock/${data.id}`,
+		method: 'GET',
+	});
+}
+// 参与质押
+export function lockJoin(data) {
+	return request({
+		url: `/api/lock/${data.id}`,
+		method: 'POST',
+		data
+	});
+}

+ 147 - 0
api/order.js

@@ -0,0 +1,147 @@
+import request from '@/utils/request'
+import {upFilse} from '@/utils/request'
+// 订单确认
+export function confirm(data) {
+	return request({
+		url: '/api/order/confirm',
+		method: 'post',
+		data
+	});
+}
+//获取可使用优惠券
+export function couponsOrder(data,price) {
+	return request({
+		url: '/api/coupons/order/'+price,
+		method: 'get',
+		data
+	});
+}
+//获取优惠券列表
+export function getCouponsList(data,types) {
+	//优惠券状态 0全部 1未使用 2已使用
+	return request({
+		url: '/api/coupons/user/'+types,
+		method: 'get',
+		data
+	});
+}
+//提交评论
+export function order_comment(data) {
+	return request({
+		url: '/api/order/comment',
+		method: 'post',
+		data
+	});
+}
+//订单产品信息
+export function product(data) {
+	return request({
+		url: '/api/order/product',
+		method: 'post',
+		data
+	});
+}
+// 快递查询
+export function express_query(data) {
+	return request({
+		url: '/api/order/express_query',
+		method: 'get',
+		data
+	});
+}
+//上传图片
+export function upload(data) {
+	return upFilse({
+		url: '/api/upload/image',
+		method: 'post',
+		data
+	});
+}
+// 订单列表
+export function orderList(data) {
+	return request({
+		url: '/api/order/list',
+		method: 'get',
+		data
+	});
+}
+// 订单详细
+export function orderDetail(data,orderid) {
+	return request({
+		url: '/api/order/detail/'+orderid,
+		method: 'get',
+		data
+	});
+}
+
+// 取消订单
+export function orderCancel(data) {
+	return request({
+		url: '/api/order/cancel',
+		method: 'post',
+		data
+	});
+}
+
+// 删除订单
+export function orderDel(data) {
+	return request({
+		url: '/api/order/del',
+		method: 'get',
+		data
+	});
+}
+// 申请退款
+export function refund(data) {
+	return request({
+		url: '/api/order/refund/verify',
+		method: 'post',
+		data
+	});
+}
+// 退款理由列表
+export function refundReason(data) {
+	return request({
+		url: '/api/order/refund/reason',
+		method: 'get',
+		data
+	});
+}
+
+// 确认收货
+export function orderTake(data) {
+	return request({
+		url: '/api/order/take',
+		method: 'post',
+		data
+	});
+}
+
+// 订单支付
+export function orderPay(data) {
+	return request({
+		url: '/api/order/pay',
+		method: 'post',
+		data
+	});
+}
+
+// 创建订单
+export function createOrderkey(data,key) {
+	return request({
+		url: '/api/order/create/'+key,
+		method: 'post',
+		data
+	});
+}
+
+// 统计订单金额
+export function computedOrderkey(data) {
+	return request({
+		url: '/api/order/computed/'+data.orderkey,
+		method: 'post',
+		data
+	});
+}
+
+

+ 194 - 0
api/product.js

@@ -0,0 +1,194 @@
+import request from '@/utils/request'
+
+// 获取商品列表
+export function getProducts(data) {
+	// 	{
+	// 参数名称	是否必须	示例	备注
+	// sid			否			二级分类编号
+	// cid			否			一级分类编号(!)
+	// keyword		否			搜索
+	// priceOrder	否			价格排序
+	// salesOrder	否			销量排序
+	// news			否			是否新品
+	// page			否			分页参数起始值
+	// limit		否			分页数步长值
+	// }
+	return request({
+		url: '/api/products',
+		method: 'get',
+		data
+	});
+}
+// 获取商品详情
+export function goodsDetail(data, id) {
+	return request({
+		url: '/api/product/detail/' + id,
+		method: 'get',
+		data
+	});
+}
+
+// 砍价列表
+export function getBargainList(data) {
+	return request({
+		url: '/api/bargain/list',
+		method: 'get',
+		data
+	});
+}
+// 加入购物车
+export function cartAdd(data) {
+	return request({
+		url: '/api/cart/add',
+		method: 'post',
+		data
+	});
+}
+
+// 收藏商品
+export function collectAdd(data) {
+	return request({
+		url: '/api/collect/add',
+		method: 'post',
+		data
+	});
+}
+
+// 取消收藏商品
+export function collectDel(data) {
+	return request({
+		url: '/api/collect/del',
+		method: 'post',
+		data
+	});
+}
+
+// 获取搜搜关键字
+export function searchKeyword(data) {
+	return request({
+		url: '/api/search/keyword',
+		method: 'get',
+		data
+	});
+}
+
+// 获取热门分类信息
+export function groomList(data, type) {
+	// 获取产品类型 1 精品推荐 2 热门榜单 3首发新品 4促销单品
+	return request({
+		url: '/api/groom/list/' + type,
+		method: 'get',
+		data
+	});
+}
+
+
+// 获取秒杀商品详细
+export function seckillGoods(data, id) {
+	return request({
+		url: '/api/seckill/detail/' + id,
+		method: 'get',
+		data
+	});
+}
+
+// 获取拼团商品详细
+export function groupGoods(data, id) {
+	return request({
+		url: '/api/combination/detail/' + id,
+		method: 'get',
+		data
+	});
+}
+
+
+// 获取商品分类
+export function getCategoryList(data) {
+	return request({
+		url: '/api/category',
+		method: 'get',
+		data
+	});
+}
+
+
+// 获取拼团列表
+export function getCombinationList(data) {
+	return request({
+		url: '/api/combination/list',
+		method: 'get',
+		data
+	});
+}
+
+//取消拼团
+export function getCombinationLisRemove(data, id) {
+	return request({
+		url: '/api/combination/remove' + id,
+		method: 'get',
+		data
+	});
+}
+
+//拼团开团页面数据
+export function getCombinationLisPink(data, id) {
+	return request({
+		url: '/api/combination/pink/' + id,
+		method: 'get',
+		data
+	});
+}
+
+// 获取拼团海报
+export function getCombinationPoster(data) {
+	return request({
+		url: '/api/combination/poster',
+		method: 'post',
+		data
+	});
+}
+
+
+// 获取秒杀分类
+export function getSeckillClass(data) {
+	return request({
+		url: '/api/seckill/index',
+		method: 'get',
+		data
+	});
+}
+// 获取秒杀列表
+export function getSeckillList(data, id) {
+	return request({
+		url: '/api/seckill/list/' + id,
+		method: 'get',
+		data
+	});
+}
+
+
+// 产品评价数量和好评度
+export function reply_config(data, id) {
+	return request({
+		url: '/api/reply/config/' + id,
+		method: 'get',
+		data
+	});
+}
+// 获取产品评论
+export function reply_list(data, id) {
+	return request({
+		url: '/api/reply/list/' + id,
+		method: 'get',
+		data
+	});
+}
+
+// 分享海报 
+export function poster(data) {
+	return request({
+		url: '/api/product/poster',
+		method: 'post',
+		data
+	});
+}

+ 56 - 0
api/set.js

@@ -0,0 +1,56 @@
+import request from '@/utils/request'
+
+// 修改用户信息
+export function userEdit(data) {
+	return request({
+		// url: '/api/password/reset/trade_password',
+		url: '/api/user/edit',
+		method: 'post',
+		data
+	});
+}
+
+//退出登录
+export function logout(data) {
+	return request({
+		url: '/api/logout',
+		method: 'get',
+		data
+	});
+}
+//修改密码
+export function registerReset(data) {
+	return request({
+		url: '/api/register/reset',
+		method: 'post',
+		data
+	});
+}
+
+//修改交易密码
+export function Reset(data) {
+	return request({
+		url: '/api/password/reset/trade_password',
+		method: 'post',
+		data
+	});
+}
+
+//绑定手机
+export function binding(data) {
+	return request({
+		url: '/api/binding',
+		method: 'post',
+		data
+	});
+}
+// #ifdef APP-PLUS
+//苹果生成账户
+export function applelogin(data) {
+	return request({
+		url: '/api/applelogin',
+		method: 'post',
+		data
+	});
+}
+// #endif

+ 194 - 0
api/user.js

@@ -0,0 +1,194 @@
+import request from '@/utils/request'
+
+// 获取用户信息
+export function getUserInfo(data) {
+	return request({
+		url: '/api/userinfo',
+		method: 'get',
+		data
+	});
+}
+
+// 
+export function getUser(data) {
+	return request({
+		url: '/api/user',
+		method: 'get',
+		data
+	});
+}
+
+//用户推荐用户列表
+export function spread_se(data,id) {
+	return request({
+		url: `/api/spread/people/${id}`,
+		method: 'get',
+		data
+	});
+}
+
+
+//用户推荐用户列表
+export function spread(data) {
+	return request({
+		url: `/api/spread/people`,
+		method: 'post',
+		data
+	});
+}
+
+// 订单统计信息
+export function orderData(data) {
+	return request({
+		url: '/api/order/data',
+		method: 'get',
+		data
+	});
+}
+
+
+
+// 用户分享图
+export function spreadBanner(data) {
+	return request({
+		url: '/api/spread/banner',
+		method: 'get',
+		data
+	});
+}
+
+// 获取地址列表
+export function getAddressList(data) {
+	return request({
+		url: '/api/address/list',
+		method: 'get',
+		data
+	});
+}
+// 修改地址
+export function addressEdit(data) {
+	return request({
+		url: '/api/address/edit',
+		method: 'post',
+		data
+	});
+}
+// 删除地址
+export function addressDel(data) {
+	return request({
+		url: '/api/address/del',
+		method: 'post',
+		data
+	});
+}
+// 设为默认地址
+export function setAddressDefault(data) {
+	return request({
+		url: '/api/address/default/set',
+		method: 'post',
+		data
+	});
+}
+// 购物车列表
+export function getCartList(data) {
+	return request({
+		url: '/api/cart/list',
+		method: 'get',
+		data
+	});
+}
+
+// 修改购物车数量
+export function getCartNum(data) {
+	return request({
+		url: '/api/cart/num',
+		method: 'post',
+		data
+	});
+}
+//删除购物车
+export function cartDel(data) {
+	return request({
+		url: '/api/cart/del',
+		method: 'post',
+		data
+	});
+}
+//获取收藏夹列表
+export function getcollectList(data) {
+	return request({
+		url: '/api/collect/user',
+		method: 'get',
+		data
+	});
+}
+// 取消收藏
+export function delcollect(data) {
+	return request({
+		url: '/api/collect/del',
+		method: 'post',
+		data
+	});
+}
+
+
+//http://hmd.frp.liuniu946.com/api/brokerage/list?page=1&limit=10&pm=1
+export function getCommissionInfo(data) {
+	return request({
+		url: '/api/brokerage/list',
+		method: 'get',
+		data
+	});
+}
+
+//我的推广
+export function myspread(data) {
+	return request({
+		url: '/api/spread/people',
+		method: 'POST',
+		data
+	});
+}
+
+
+//
+export function sqdl(data) {
+	return request({
+		url: '/api/user/apply',
+		method: 'POST',
+		data
+	});
+}
+
+export function details(data, id) {
+	return request({
+		url: '/api/article/details/' + id,
+		method: 'get',
+		data
+	});
+}
+
+export function yjzye(data) {
+	return request({
+		url: '/api/user/transformation',
+		method: 'post',
+		data
+	})
+}
+
+export function jfzz(data) {
+	return request({
+		url: '/api/brokeragePriceTransfer',
+		method: 'post',
+		data
+	})
+}
+
+export function getLevelList(data) {
+	// api/give_level_list
+	return request({
+		url: '/api/give_level_list',
+		method: 'get',
+		data
+	})
+}

+ 159 - 0
api/wallet.js

@@ -0,0 +1,159 @@
+import request from '@/utils/request'
+
+// 获取用户消费记录
+export function spreadCommission(data, state) {
+	return request({
+		url: '/api/spread/commission/' + state,
+		method: 'get',
+		data
+	});
+}
+
+// 获取账户余额
+export function userBalance(data) {
+	return request({
+		url: '/api/user/balance',
+		method: 'get',
+		data
+	});
+}
+
+// 提现
+export function extractCash(data) {
+	return request({
+		url: '/api/extract/cash',
+		method: 'post',
+		data
+	});
+}
+
+// 提现信息
+export function extractBank(data) {
+	return request({
+		url: '/api/extract/bank',
+		method: 'get',
+		data
+	});
+}
+// #ifdef H5
+// 公众号充值
+export function rechargeWechat(data) {
+	return request({
+		url: '/api/recharge/wechat',
+		method: 'post',
+		data
+	});
+}
+// #endif
+// #ifdef MP
+// 小程序充值
+export function rechargeRoutine(data) {
+	return request({
+		url: '/api/recharge/routine',
+		method: 'post',
+		data
+	});
+}
+// #endif
+// 获取提现支付宝账号
+export function aliInfo(data) {
+	return request({
+		url: '/api/ali/info',
+		method: 'get',
+		data
+	});
+}
+//获取默认银行卡账号
+export function bankInfo(data) {
+	return request({
+		url: '/api/bank/info',
+		method: 'get',
+		data
+	});
+}
+// 保存提现支付宝账号
+export function setAliInfo(data) {
+	return request({
+		url: '/api/ali/edit',
+		method: 'post',
+		data
+	});
+}
+//保存默认银行卡账号
+export function setBankInfo(data) {
+	return request({
+		url: '/api/bank/edit',
+		method: 'post',
+		data
+	});
+}
+
+
+// 账户余额
+export function balance(data) {
+	return request({
+		url: '/api/user/balance',
+		method: 'get',
+		data
+	});
+}
+
+//
+export function yue(data) {
+	return request({
+		url: '/api/now_money/list',
+		method: 'get',
+		data
+	});
+}
+
+export function integral(data) {
+	return request({
+		url: '/api/integral/list',
+		method: 'get',
+		data
+	});
+}
+
+export function getBank(data) {
+	return request({
+		url: '/api/auction/pay_list',
+		method: 'get',
+		data
+	});
+}
+
+export function setBank(data) {
+	return request({
+		url: '/api/auction/pay',
+		method: 'post',
+		data
+	});
+}
+
+export function getRechargePrice(data) {
+	return request({
+		url: '/api/getRechargePrice',
+		method: 'post',
+		data
+	});
+}
+
+// 竞猜项目api
+export function qianBao(data) {
+	return request({
+		url: '/api/wallet',
+		method: 'get',
+		data
+	});
+}
+
+
+// 钱包USDT类型交易明细
+export function getMoneyLog(data,money_type='USDT') {
+	return request({
+		url: `/api/money/log/${money_type}`,
+		method: 'get',
+		data
+	});
+}

+ 37 - 0
api/wx.js

@@ -0,0 +1,37 @@
+import request from '@/utils/request'
+// #ifdef H5
+// 微信分享信息
+export function share(data) {
+	return request({
+		url: '/api/share',
+		method: 'get',
+		data
+	});
+}
+//微信配置
+export function wechatConfig(data) {
+	return request({
+		url: '/api/wechat/config',
+		method: 'get',
+		data
+	});
+}
+// 微信code地址
+export function wechatAuth(data) {
+	return request({
+		url: '/api/wechat/auth',
+		method: 'get',
+		data
+	});
+}
+// #endif
+// #ifdef MP-WEIXIN
+// 微信code地址
+export function wechatMpAuth(data) {
+	return request({
+		url: '/api/wechat/mp_auth',
+		method: 'post',
+		data
+	});
+}
+// #endif

File diff suppressed because it is too large
+ 18 - 0
components/empty.vue


+ 77 - 0
components/footer/footer.vue

@@ -0,0 +1,77 @@
+<template>
+	<view class="footer flex p-y-xs2 bg-tab-nav">
+		<view class="flex-fill" :class="{ 'router-link-active': tab == item.tel }"
+			v-for="item in navList" :key="item.tel" @click="tabChange(item.tel)">
+			<view class="icon">
+				<img class="h-15" v-if="tab == item.tel" :src="item.activeIcon" alt="" />
+				<img class="h-15" v-else :src="item.icon" alt="" />
+			</view>
+			<view class="fn-12">{{ $t(item.label) }}</view>
+		</view>
+	</view>
+</template>
+<script>
+	import {
+		navList
+	} from "./list.js";
+	export default {
+		props: {
+			tab: {
+				type: String,
+				default: "index",
+			},
+		},
+		data() {
+			return {
+				navList: navList(this),
+			};
+		},
+		created() {
+			// console.log(navList,'navList');
+		},
+		methods: {
+			tabChange(v) {
+				uni.switchTab({
+					url: "/pages/index/" + v,
+				});
+				// console.log(v);
+				// console.log(this.$router);
+			},
+		},
+	};
+</script>
+<style lang="scss" scoped>
+	.flex-fill{
+		text-align: center;
+		line-height: 1;
+	}
+	.p-y-xs2 {
+		padding: 5px 10px;
+	}
+	.h-15{
+		height: 20px;
+		width: 20px;
+	}
+	.footer {
+		box-shadow:  0px -7px 20px 0px rgba(37, 37, 48, 0.83);
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		z-index: 999 !important;
+		// height: 102rpx;
+		color: rgba(#fff, 0.3);
+		justify-content: space-around !important;
+	}
+	.fn-12{
+		margin-top: 4px;
+		font-size: 10px;
+	}
+	.router-link-active {
+		// color: $theme-1;
+		color:#FEB041;
+	}
+
+	.bg-tab-nav {
+		background-color: #000000;
+	}
+</style>

+ 34 - 0
components/footer/list.js

@@ -0,0 +1,34 @@
+export function navList(that) {
+  return [
+    {
+      label: "home.d0",
+      tel: "index",
+      icon: "static/tabBar/shouye.png",
+      activeIcon: "static/tabBar/shouye-home.png",
+    },
+    {
+      label: "home.d1",
+      tel: "pledge",
+      icon: "static/tabBar/baoya.png",
+      activeIcon: "static/tabBar/baoya-home.png",
+    },
+	// {
+	//   label: "home.d2",
+	//   tel: "entertainment",
+	//   icon: "static/tabBar/huyu.png",
+	//   activeIcon: "static/tabBar/huyu-home.png",
+	// },
+    {
+      label: "home.d3",
+      tel: "information",
+      icon: "static/tabBar/zixun.png",
+      activeIcon: "static/tabBar/zixun-home.png",
+    },
+    {
+      label: "home.d4",
+      tel: "user",
+      icon: "static/tabBar/my.png",
+      activeIcon: "static/tabBar/my-home.png",
+    },
+  ];
+}

+ 123 - 0
components/input-password/input-password.vue

@@ -0,0 +1,123 @@
+<template>
+	<view class="page">
+		<view>
+			<view class="pay-title">
+				<text>{{$t('enter.b3')}}</text>
+			</view>
+			<view class="pay-password">
+				<view class="list" v-for="item in 6">
+					<text v-show="passwordArr.length >= item">●</text>
+				</view>
+			</view>
+			<navigator url="/pages/user/set/transaction">
+				<view class="hint">
+					<text>{{$t('login.b8')}}</text>
+				</view>
+			</navigator>
+		</view>
+		<cc-defineKeyboard ref="CodeKeyboard" passwrdType="pay" @KeyInfo="KeyInfo" :viewShow="true"></cc-defineKeyboard>
+	</view>
+</template>
+<script>
+	export default {
+		data() {
+			return {
+				passwordArr: []
+			};
+		},
+		mounted() {
+			this.$refs.CodeKeyboard.show();
+		},
+		// 关闭循环
+		methods: {
+			// 点击触发支付事件
+			KeyInfo(val) {
+				console.log(val);
+				let arr = this.passwordArr;
+				if (val.index >= 6) {
+					return;
+				}
+				// 判断是否输入的是删除键
+				if (val.keyCode === 8) {
+					// 删除最后一位
+					arr.splice(val.index + 1, 1)
+				}
+				// 判断是否输入的是取消案件
+				else if (val.keyCode == 190) {
+					this.$emit('colse')
+				} else {
+					arr.push(val.key);
+				}
+				// 开始交易
+				if (arr.length == 6) {
+					this.$emit('commit',this.passwordArr.join(''))
+					//初始化对象
+					this.passwordArr = [];
+				}
+			},
+		},
+	};
+</script>
+
+<style lang="scss">
+	$base: orangered; // 基础颜色
+
+	.page {
+		width: 100%;
+		background-color: #FFFFFF;
+
+		.pay-title {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			width: 100%;
+			height: 200rpx;
+
+			text {
+				font-size: 28rpx;
+				color: #555555;
+			}
+		}
+
+		.pay-password {
+			display: flex;
+			align-items: center;
+			width: 90%;
+			height: 80rpx;
+			margin: 20rpx auto;
+			border: 2rpx solid $base;
+
+			.list {
+				color: #555555;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 16.666%;
+				height: 100%;
+				border-right: 2rpx solid #EEEEEE;
+
+				text {
+					font-size: 32rpx;
+				}
+			}
+
+			.list:nth-child(6) {
+				border-right: none;
+			}
+		}
+
+		.hint {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			width: 100%;
+			height: 100rpx;
+
+			text {
+				font-size: 28rpx;
+				color: $base;
+			}
+		}
+	}
+
+</style>

+ 814 - 0
components/jyf-parser/jyf-parser.vue

@@ -0,0 +1,814 @@
+<!--
+  parser 主模块组件
+  github:https://github.com/jin-yufeng/Parser 
+  docs:https://jin-yufeng.github.io/Parser
+  插件市场:https://ext.dcloud.net.cn/plugin?id=805
+  author:JinYufeng
+  update:2020/04/14
+-->
+<template>
+	<view>
+		<slot v-if="!nodes.length" />
+		<!--#ifdef APP-PLUS-NVUE-->
+		<web-view id="top" ref="web" :src="src" :style="'margin-top:-2px;height:'+height+'px'" @onPostMessage="_message" />
+		<!--#endif-->
+		<!--#ifndef APP-PLUS-NVUE-->
+		<view id="top" :style="showAm+(selectable?';user-select:text;-webkit-user-select:text':'')" :animation="scaleAm" @tap="_tap"
+		 @touchstart="_touchstart" @touchmove="_touchmove">
+			<!--#ifdef H5-->
+			<div :id="'rtf'+uid"></div>
+			<!--#endif-->
+			<!--#ifndef H5-->
+			<trees :nodes="nodes" :lazy-load="lazyLoad" :loadVideo="loadVideo" />
+			<image v-for="(item, index) in imgs" v-bind:key="index" :id="index" :src="item" hidden @load="_load" />
+			<!--#endif-->
+		</view>
+		<!--#endif-->
+	</view>
+</template>
+
+<script>
+	// #ifndef H5 || APP-PLUS-NVUE
+	import trees from './libs/trees';
+	var cache = {},
+		// #ifdef MP-WEIXIN || MP-TOUTIAO
+		fs = uni.getFileSystemManager ? uni.getFileSystemManager() : null,
+		// #endif
+		Parser = require('./libs/MpHtmlParser.js');
+	var document; // document 补丁包 https://jin-yufeng.github.io/Parser/#/instructions?id=document
+	// 计算 cache 的 key
+	function hash(str) {
+		for (var i = str.length, val = 5381; i--;)
+			val += (val << 5) + str.charCodeAt(i);
+		return val;
+	}
+	// #endif
+	// #ifdef H5 || APP-PLUS-NVUE
+	var rpx = uni.getSystemInfoSync().screenWidth / 750,
+		cfg = require('./libs/config.js');
+	// #endif
+	// #ifdef APP-PLUS-NVUE
+	var dom = weex.requireModule('dom');
+	// #endif
+	export default {
+		name: 'parser',
+		data() {
+			return {
+				// #ifdef APP-PLUS
+				loadVideo: false,
+				// #endif
+				// #ifdef H5
+				uid: this._uid,
+				// #endif
+				// #ifdef APP-PLUS-NVUE
+				src: '',
+				height: 1,
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				scaleAm: '',
+				showAm: '',
+				imgs: [],
+				// #endif
+				nodes: []
+			}
+		},
+		// #ifndef H5 || APP-PLUS-NVUE
+		components: {
+			trees
+		},
+		// #endif
+		props: {
+			'html': null,
+			// #ifndef MP-ALIPAY
+			'autopause': {
+				type: Boolean,
+				default: true
+			},
+			// #endif
+			'autosetTitle': {
+				type: Boolean,
+				default: true
+			},
+			// #ifndef H5 || APP-PLUS-NVUE
+			'compress': Number,
+			'useCache': Boolean,
+			'xml': Boolean,
+			// #endif
+			'domain': String,
+			// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+			'gestureZoom': Boolean,
+			// #endif
+			// #ifdef MP-WEIXIN || MP-QQ || H5 || APP-PLUS
+			'lazyLoad': Boolean,
+			// #endif
+			'selectable': Boolean,
+			'tagStyle': Object,
+			'showWithAnimation': Boolean,
+			'useAnchor': Boolean
+		},
+		watch: {
+			html(html) {
+				this.setContent(html);
+			}
+		},
+		mounted() {
+			// 图片数组
+			this.imgList = [];
+			this.imgList.each = function(f) {
+				for (var i = 0, len = this.length; i < len; i++)
+					this.setItem(i, f(this[i], i, this));
+			}
+			this.imgList.setItem = function(i, src) {
+				if (i == void 0 || !src) return;
+				// #ifndef MP-ALIPAY || APP-PLUS
+				// 去重
+				if (src.indexOf('http') == 0 && this.includes(src)) {
+					var newSrc = '';
+					for (var j = 0, c; c = src[j]; j++) {
+						if (c == '/' && src[j - 1] != '/' && src[j + 1] != '/') break;
+						newSrc += Math.random() > 0.5 ? c.toUpperCase() : c;
+					}
+					newSrc += src.substr(j);
+					return this[i] = newSrc;
+				}
+				// #endif
+				this[i] = src;
+				// 暂存 data src
+				if (src.includes('data:image')) {
+					var filePath, info = src.match(/data:image\/(\S+?);(\S+?),(.+)/);
+					if (!info) return;
+					// #ifdef MP-WEIXIN || MP-TOUTIAO
+					filePath = `${wx.env.USER_DATA_PATH}/${Date.now()}.${info[1]}`;
+					fs && fs.writeFile({
+						filePath,
+						data: info[3],
+						encoding: info[2],
+						success: () => this[i] = filePath
+					})
+					// #endif
+					// #ifdef APP-PLUS
+					filePath = `_doc/parser_tmp/${Date.now()}.${info[1]}`;
+					var bitmap = new plus.nativeObj.Bitmap();
+					bitmap.loadBase64Data(src, () => {
+						bitmap.save(filePath, {}, () => {
+							bitmap.clear()
+							this[i] = filePath;
+						})
+					})
+					// #endif
+				}
+			}
+			if (this.html) this.setContent(this.html);
+		},
+		beforeDestroy() {
+			// #ifdef H5
+			if (this._observer) this._observer.disconnect();
+			// #endif
+			this.imgList.each(src => {
+				// #ifdef APP-PLUS
+				if (src && src.includes('_doc')) {
+					plus.io.resolveLocalFileSystemURL(src, entry => {
+						entry.remove();
+					});
+				}
+				// #endif
+				// #ifdef MP-WEIXIN || MP-TOUTIAO
+				if (src && uni.env && src.includes(uni.env.USER_DATA_PATH))
+					fs && fs.unlink({
+						filePath: src
+					})
+				// #endif
+			})
+			clearInterval(this._timer);
+		},
+		methods: {
+			// #ifdef H5 || APP-PLUS-NVUE
+			_Dom2Str(nodes) {
+				var str = '';
+				for (var node of nodes) {
+					if (node.type == 'text')
+						str += node.text;
+					else {
+						str += ('<' + node.name);
+						for (var attr in node.attrs || {})
+							str += (' ' + attr + '="' + node.attrs[attr] + '"');
+						if (!node.children || !node.children.length) str += '>';
+						else str += ('>' + this._Dom2Str(node.children) + '</' + node.name + '>');
+					}
+				}
+				return str;
+			},
+			_handleHtml(html, append) {
+				if (typeof html != 'string') html = this._Dom2Str(html.nodes || html);
+				// 处理 rpx
+				if (html.includes('rpx'))
+					html = html.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * rpx + 'px');
+				if (!append) {
+					// 处理 tag-style 和 userAgentStyles
+					var style = '<style>@keyframes show{0%{opacity:0}100%{opacity:1}}';
+					for (var item in cfg.userAgentStyles)
+						style += `${item}{${cfg.userAgentStyles[item]}}`;
+					for (item in this.tagStyle)
+						style += `${item}{${this.tagStyle[item]}}`;
+					style += '</style>';
+					html = style + html;
+				}
+				return html;
+			},
+			// #endif
+			setContent(html, append) {
+				// #ifdef APP-PLUS-NVUE
+				if (!html) {
+					this.src = '';
+					this.height = 1;
+					return;
+				}
+				if (append) return;
+				plus.io.resolveLocalFileSystemURL('_doc', entry => {
+					entry.getDirectory('parser_tmp', {
+						create: true
+					}, entry => {
+						var fileName = Date.now() + '.html';
+						entry.getFile(fileName, {
+							create: true
+						}, entry => {
+							entry.createWriter(writer => {
+								writer.onwriteend = () => {
+									this.nodes = [1];
+									this.src = '_doc/parser_tmp/' + fileName;
+									this.$nextTick(function() {
+										entry.remove();
+									})
+								}
+								html =
+									'<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1' +
+									(this.selectable ? '' : ',user-scalable=no') +
+									'"><script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></' +
+									'script><base href="' + this.domain + '">' + this._handleHtml(html) +
+									'<script>"use strict";function post(t){uni.postMessage({data:t})}' +
+									(this.showWithAnimation ? 'document.body.style.animation="show .5s",' : '') +
+									'document.addEventListener("UniAppJSBridgeReady",function(){post({action:"load",text:document.body.innerText});var t=document.getElementsByTagName("title");t.length&&post({action:"getTitle",title:t[0].innerText});for(var e,o=document.getElementsByTagName("img"),n=[],i=0,r=0;e=o[i];i++)e.onerror=function(){post({action:"error",source:"img",target:this})},e.hasAttribute("ignore")||"A"==e.parentElement.nodeName||(e.i=r++,n.push(e.src),e.onclick=function(){post({action:"preview",img:{i:this.i,src:this.src}})});post({action:"getImgList",imgList:n});for(var a,s=document.getElementsByTagName("a"),c=0;a=s[c];c++)a.onclick=function(){var t,e=this.getAttribute("href");if("#"==e[0]){var r=document.getElementById(e.substr(1));r&&(t=r.offsetTop)}return post({action:"linkpress",href:e,offset:t}),!1};;for(var u,m=document.getElementsByTagName("video"),d=0;u=m[d];d++)u.style.maxWidth="100%",u.onerror=function(){post({action:"error",source:"video",target:this})}' +
+									(this.autopause ? ',u.onplay=function(){for(var t,e=0;t=m[e];e++)t!=this&&t.pause()}' : '') +
+									';for(var g,l=document.getElementsByTagName("audio"),p=0;g=l[p];p++)g.onerror=function(){post({action:"error",source:"audio",target:this})};window.onload=function(){post({action:"ready",height:document.body.scrollHeight})}});</' +
+									'script>';
+								writer.write(html);
+							});
+						})
+					})
+				})
+				// #endif
+				// #ifdef H5
+				if (!html) {
+					if (this.rtf && !append) this.rtf.parentNode.removeChild(this.rtf);
+					return;
+				}
+				var div = document.createElement('div');
+				if (!append) {
+					if (this.rtf) this.rtf.parentNode.removeChild(this.rtf);
+					this.rtf = div;
+				} else {
+					if (!this.rtf) this.rtf = div;
+					else this.rtf.appendChild(div);
+				}
+				div.innerHTML = this._handleHtml(html, append);
+				for (var styles = this.rtf.getElementsByTagName('style'), i = 0, style; style = styles[i++];) {
+					style.innerHTML = style.innerHTML.replace(/body/g, '#rtf' + this._uid);
+					style.setAttribute('scoped', 'true');
+				}
+				// 懒加载
+				if (!this._observer && this.lazyLoad && IntersectionObserver) {
+					this._observer = new IntersectionObserver(changes => {
+						for (let item, i = 0; item = changes[i++];) {
+							if (item.isIntersecting) {
+								item.target.src = item.target.getAttribute('data-src');
+								item.target.removeAttribute('data-src');
+								this._observer.unobserve(item.target);
+							}
+						}
+					}, {
+						rootMargin: '900px 0px 900px 0px'
+					})
+				}
+				var _ts = this;
+				// 获取标题
+				var title = this.rtf.getElementsByTagName('title');
+				if (title.length && this.autosetTitle)
+					uni.setNavigationBarTitle({
+						title: title[0].innerText
+					})
+				// 图片处理
+				this.imgList.length = 0;
+				var imgs = this.rtf.getElementsByTagName('img');
+				for (let i = 0, j = 0, img; img = imgs[i]; i++) {
+					img.style.maxWidth = '100%';
+					var src = img.getAttribute('src');
+					if (this.domain && src) {
+						if (src[0] == '/') {
+							if (src[1] == '/')
+								img.src = (this.domain.includes('://') ? this.domain.split('://')[0] : '') + ':' + src;
+							else img.src = this.domain + src;
+						} else if (!src.includes('://')) img.src = this.domain + '/' + src;
+					}
+					if (!img.hasAttribute('ignore') && img.parentElement.nodeName != 'A') {
+						img.i = j++;
+						_ts.imgList.push(img.src || img.getAttribute('data-src'));
+						img.onclick = function() {
+							var preview = true;
+							this.ignore = () => preview = false;
+							_ts.$emit('imgtap', this);
+							if (preview) {
+								uni.previewImage({
+									current: this.i,
+									urls: _ts.imgList
+								});
+							}
+						}
+					}
+					img.onerror = function() {
+						_ts.$emit('error', {
+							source: 'img',
+							target: this
+						});
+					}
+					if (_ts.lazyLoad && this._observer && img.src && img.i != 0) {
+						img.setAttribute('data-src', img.src);
+						img.removeAttribute('src');
+						this._observer.observe(img);
+					}
+				}
+				// 链接处理
+				var links = this.rtf.getElementsByTagName('a');
+				for (var link of links) {
+					link.onclick = function() {
+						var jump = true,
+							href = this.getAttribute('href');
+						_ts.$emit('linkpress', {
+							href,
+							ignore: () => jump = false
+						});
+						if (jump && href) {
+							if (href[0] == '#') {
+								if (_ts.useAnchor) {
+									_ts.navigateTo({
+										id: href.substr(1)
+									})
+								}
+							} else if (href.indexOf('http') == 0 || href.indexOf('//') == 0)
+								return true;
+							else {
+								uni.navigateTo({
+									url: href
+								})
+							}
+						}
+						return false;
+					}
+				}
+				// 视频处理
+				var videos = this.rtf.getElementsByTagName('video');
+				_ts.videoContexts = videos;
+				for (let video, i = 0; video = videos[i++];) {
+					video.style.maxWidth = '100%';
+					video.onerror = function() {
+						_ts.$emit('error', {
+							source: 'video',
+							target: this
+						});
+					}
+					video.onplay = function() {
+						if (_ts.autopause)
+							for (let item, i = 0; item = _ts.videoContexts[i++];)
+								if (item != this) item.pause();
+					}
+				}
+				// 音频处理
+				var audios = this.rtf.getElementsByTagName('audios');
+				for (var audio of audios)
+					audio.onerror = function() {
+						_ts.$emit('error', {
+							source: 'audio',
+							target: this
+						});
+					}
+				this.document = this.rtf;
+				if (!append) document.getElementById('rtf' + this._uid).appendChild(this.rtf);
+				this.$nextTick(() => {
+					this.nodes = [1];
+					this.$emit('load');
+				})
+				setTimeout(() => this.showAm = '', 500);
+				// #endif
+				// #ifndef H5 || APP-PLUS-NVUE
+				var nodes;
+				if (!html)
+					return this.nodes = [];
+				else if (typeof html == 'string') {
+					let parser = new Parser(html, this);
+					// 缓存读取
+					if (this.useCache) {
+						var hashVal = hash(html);
+						if (cache[hashVal])
+							nodes = cache[hashVal];
+						else {
+							nodes = parser.parse();
+							cache[hashVal] = nodes;
+						}
+					} else nodes = parser.parse();
+					this.$emit('parse', nodes);
+				} else if (Object.prototype.toString.call(html) == '[object Array]') {
+					// 非本插件产生的 array 需要进行一些转换
+					if (html.length && html[0].PoweredBy != 'Parser') {
+						let parser = new Parser(html, this);
+						(function f(ns) {
+							for (var i = 0, n; n = ns[i]; i++) {
+								if (n.type == 'text') continue;
+								n.attrs = n.attrs || {};
+								for (var item in n.attrs)
+									if (typeof n.attrs[item] != 'string') n.attrs[item] = n.attrs[item].toString();
+								parser.matchAttr(n, parser);
+								if (n.children && n.children.length) {
+									parser.STACK.push(n);
+									f(n.children);
+									parser.popNode(parser.STACK.pop());
+								} else n.children = void 0;
+							}
+						})(html);
+					}
+					nodes = html;
+				} else if (typeof html == 'object' && html.nodes) {
+					nodes = html.nodes;
+					console.warn('错误的 html 类型:object 类型已废弃');
+				} else
+					return console.warn('错误的 html 类型:' + typeof html);
+				// #ifdef APP-PLUS
+				this.loadVideo = false;
+				// #endif
+				if (document) this.document = new document(this.nodes, 'nodes', this);
+				if (append) this.nodes = this.nodes.concat(nodes);
+				else this.nodes = nodes;
+				if (nodes.length && nodes[0].title && this.autosetTitle)
+					uni.setNavigationBarTitle({
+						title: nodes[0].title
+					})
+				this.$nextTick(() => {
+					this.imgList.length = 0;
+					this.videoContexts = [];
+					// #ifdef MP-TOUTIAO
+					setTimeout(() => {
+						// #endif
+						var f = (cs) => {
+							for (let i = 0, c; c = cs[i++];) {
+								if (c.$options.name == 'trees') {
+									for (var j = c.nodes.length, item; item = c.nodes[--j];) {
+										if (item.c) continue;
+										if (item.name == 'img') {
+											this.imgList.setItem(item.attrs.i, item.attrs.src);
+											// #ifndef MP-ALIPAY
+											if (!c.observer && !c.imgLoad && item.attrs.i != '0') {
+												if (this.lazyLoad && uni.createIntersectionObserver) {
+													c.observer = uni.createIntersectionObserver(c);
+													c.observer.relativeToViewport({
+														top: 900,
+														bottom: 900
+													}).observe('._img', () => {
+														c.imgLoad = true;
+														c.observer.disconnect();
+													})
+												} else
+													c.imgLoad = true;
+											}
+											// #endif
+										}
+										// #ifndef MP-ALIPAY
+										else if (item.name == 'video') {
+											var ctx = uni.createVideoContext(item.attrs.id, c);
+											ctx.id = item.attrs.id;
+											this.videoContexts.push(ctx);
+										}
+										// #endif
+										// #ifdef MP-BAIDU || MP-ALIPAY || APP-PLUS
+										if (item.attrs && item.attrs.id) {
+											this.anchors = this.anchors || [];
+											this.anchors.push({
+												id: item.attrs.id,
+												node: c
+											})
+										}
+										// #endif
+									}
+								}
+								if (c.$children.length)
+									f(c.$children)
+							}
+						}
+						f(this.$children);
+						// #ifdef MP-TOUTIAO
+					}, 200)
+					this.$emit('load');
+					// #endif
+					// #ifdef APP-PLUS
+					setTimeout(() => {
+						this.loadVideo = true;
+					}, 3000);
+					// #endif
+				})
+				// #endif
+				// #ifndef APP-PLUS-NVUE
+				var height;
+				clearInterval(this._timer);
+				this._timer = setInterval(() => {
+					// #ifdef H5
+					var res = [this.rtf.getBoundingClientRect()];
+					// #endif
+					// #ifndef H5
+					// #ifdef APP-PLUS
+					uni.createSelectorQuery().in(this)
+					// #endif
+					// #ifndef APP-PLUS
+					this.createSelectorQuery()
+						// #endif
+						.select('#top').boundingClientRect().exec(res => {
+							// #endif
+							this.width = res[0].width;
+							if (res[0].height == height) {
+								this.$emit('ready', res[0])
+								clearInterval(this._timer);
+							}
+							height = res[0].height;
+							// #ifndef H5
+						});
+					// #endif
+				}, 350)
+				if (this.showWithAnimation && !append) this.showAm = 'animation:show .5s';
+				// #endif
+			},
+			getText(ns = this.nodes) {
+				// #ifdef APP-PLUS-NVUE
+				return this._text;
+				// #endif
+				// #ifdef H5
+				return this.rtf.innerText;
+				// #endif
+				// #ifndef H5 || APP-PLUS-NVUE
+				var txt = '';
+				for (var i = 0, n; n = ns[i++];) {
+					if (n.type == 'text') txt += n.text.replace(/&nbsp;/g, '\u00A0').replace(/&lt;/g, '<').replace(/&gt;/g, '>')
+						.replace(/&amp;/g, '&');
+					else if (n.type == 'br') txt += '\n';
+					else {
+						// 块级标签前后加换行
+						var block = n.name == 'p' || n.name == 'div' || n.name == 'tr' || n.name == 'li' || (n.name[0] == 'h' && n.name[1] >
+							'0' && n.name[1] < '7');
+						if (block && txt && txt[txt.length - 1] != '\n') txt += '\n';
+						if (n.children) txt += this.getText(n.children);
+						if (block && txt[txt.length - 1] != '\n') txt += '\n';
+						else if (n.name == 'td' || n.name == 'th') txt += '\t';
+					}
+				}
+				return txt;
+				// #endif
+			},
+			navigateTo(obj) {
+				if (!this.useAnchor)
+					return obj.fail && obj.fail({
+						errMsg: 'Anchor is disabled'
+					})
+				// #ifdef APP-PLUS-NVUE
+				if (!obj.id)
+					dom.scrollToElement(this.$refs.web);
+				else
+					this.$refs.web.evalJs('var pos=document.getElementById("' + obj.id +
+						'");if(pos)post({action:"linkpress",href:"#",offset:pos.offsetTop})');
+				return obj.success && obj.success({
+					errMsg: 'pageScrollTo:ok'
+				});
+				// #endif
+				// #ifdef H5
+				if (!obj.id) {
+					window.scrollTo(0, this.rtf.offsetTop);
+					return obj.success && obj.success({
+						errMsg: 'pageScrollTo:ok'
+					});
+				}
+				var target = document.getElementById(obj.id);
+				if (!target) return obj.fail && obj.fail({
+					errMsg: 'Label not found'
+				});
+				obj.scrollTop = this.rtf.offsetTop + target.offsetTop;
+				uni.pageScrollTo(obj);
+				// #endif
+				// #ifndef H5
+				var Scroll = (selector, component) => {
+					uni.createSelectorQuery().in(component ? component : this).select(selector).boundingClientRect().selectViewport()
+						.scrollOffset()
+						.exec(res => {
+							if (!res || !res[0])
+								return obj.fail && obj.fail({
+									errMsg: 'Label not found'
+								});
+							obj.scrollTop = res[1].scrollTop + res[0].top;
+							uni.pageScrollTo(obj);
+						})
+				}
+				if (!obj.id) Scroll('#top');
+				else {
+					// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+					Scroll('#top >>> #' + obj.id + ', #top >>> .' + obj.id);
+					// #endif
+					// #ifdef MP-BAIDU || MP-ALIPAY || APP-PLUS
+					for (var anchor of this.anchors)
+						if (anchor.id == obj.id)
+							Scroll('#' + obj.id + ', .' + obj.id, anchor.node);
+					// #endif
+				}
+				// #endif
+			},
+			getVideoContext(id) {
+				// #ifndef APP-PLUS-NVUE
+				if (!id) return this.videoContexts;
+				else
+					for (var i = this.videoContexts.length; i--;)
+						if (this.videoContexts[i].id == id) return this.videoContexts[i];
+				// #endif
+			},
+			// 预加载
+			preLoad(html, num) {
+				// #ifdef H5 || APP-PLUS-NVUE
+				if (html.constructor == Array)
+					html = this._Dom2Str(html);
+				var script = "var contain=document.createElement('div');contain.innerHTML='" + html.replace(/'/g, "\\'") +
+					"';for(var imgs=contain.querySelectorAll('img'),i=imgs.length-1;i>=" + num +
+					";i--)imgs[i].removeAttribute('src');";
+				// #endif
+				// #ifdef APP-PLUS-NVUE
+				this.$refs.web.evalJs(script);
+				// #endif
+				// #ifdef H5
+				eval(script);
+				// #endif
+				// #ifndef H5 || APP-PLUS-NVUE
+				if (typeof html == 'string') {
+					var id = hash(html);
+					html = new Parser(html, this).parse();
+					cache[id] = html;
+				}
+				var wait = [];
+				(function f(ns) {
+					for (var i = 0, n; n = ns[i++];) {
+						if (n.name == 'img' && n.attrs.src && !wait.includes(n.attrs.src))
+							wait.push(n.attrs.src);
+						f(n.children || []);
+					}
+				})(html);
+				if (num) wait = wait.slice(0, num);
+				this._wait = (this._wait || []).concat(wait);
+				if (!this.imgs) this.imgs = this._wait.splice(0, 15);
+				else if (this.imgs.length < 15)
+					this.imgs = this.imgs.concat(this._wait.splice(0, 15 - this.imgs.length));
+				// #endif
+			},
+			// #ifdef APP-PLUS-NVUE
+			_message(e) {
+				// 接收 web-view 消息
+				var data = e.detail.data[0];
+				if (data.action == 'load') {
+					this.$emit('load');
+					this._text = data.text;
+				} else if (data.action == 'getTitle') {
+					if (this.autosetTitle)
+						uni.setNavigationBarTitle({
+							title: data.title
+						})
+				} else if (data.action == 'getImgList') {
+					this.imgList.length = 0;
+					for (var i = data.imgList.length; i--;)
+						this.imgList.setItem(i, data.imgList[i]);
+				} else if (data.action == 'preview') {
+					var preview = true;
+					data.img.ignore = () => preview = false;
+					this.$emit('imgtap', data.img);
+					if (preview)
+						uni.previewImage({
+							current: data.img.i,
+							urls: this.imgList
+						})
+				} else if (data.action == 'linkpress') {
+					var jump = true,
+						href = data.href;
+					this.$emit('linkpress', {
+						href,
+						ignore: () => jump = false
+					})
+					if (jump && href) {
+						if (href[0] == '#') {
+							if (this.useAnchor)
+								dom.scrollToElement(this.$refs.web, {
+									offset: data.offset
+								})
+						} else if (href.includes('://'))
+							plus.runtime.openWeb(href);
+						else
+							uni.navigateTo({
+								url: href
+							})
+					}
+				} else if (data.action == 'error')
+					this.$emit('error', {
+						source: data.source,
+						target: data.target
+					})
+				else if (data.action == 'ready') {
+					this.height = data.height;
+					this.$nextTick(() => {
+						uni.createSelectorQuery().in(this).select('#top').boundingClientRect().exec(res => {
+							this.rect = res[0];
+							this.$emit('ready', res[0]);
+						})
+					})
+				}
+			},
+			// #endif
+			// #ifndef APP-PLUS-NVUE
+			// #ifndef H5
+			_load(e) {
+				if (this._wait.length)
+					this.$set(this.imgs, e.target.id, this._wait.shift());
+			},
+			// #endif
+			_tap(e) {
+				// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+				if (this.gestureZoom && e.timeStamp - this._lastT < 300) {
+					var initY = e.touches[0].pageY - e.currentTarget.offsetTop;
+					if (this._zoom) {
+						this._scaleAm.translateX(0).scale(1).step();
+						uni.pageScrollTo({
+							scrollTop: (initY + this._initY) / 2 - e.touches[0].clientY,
+							duration: 400
+						})
+					} else {
+						var initX = e.touches[0].pageX - e.currentTarget.offsetLeft;
+						this._initY = initY;
+						this._scaleAm = uni.createAnimation({
+							transformOrigin: `${initX}px ${this._initY}px 0`,
+							timingFunction: 'ease-in-out'
+						});
+						// #ifdef MP-TOUTIAO
+						this._scaleAm.opacity(1);
+						// #endif
+						this._scaleAm.scale(2).step();
+						this._tMax = initX / 2;
+						this._tMin = (initX - this.width) / 2;
+						this._tX = 0;
+					}
+					this._zoom = !this._zoom;
+					this.scaleAm = this._scaleAm.export();
+				}
+				this._lastT = e.timeStamp;
+				// #endif
+			},
+			_touchstart(e) {
+				// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+				if (e.touches.length == 1)
+					this._initX = this._lastX = e.touches[0].pageX;
+				// #endif
+			},
+			_touchmove(e) {
+				// #ifndef MP-BAIDU || MP-ALIPAY || APP-PLUS
+				var diff = e.touches[0].pageX - this._lastX;
+				if (this._zoom && e.touches.length == 1 && Math.abs(diff) > 20) {
+					this._lastX = e.touches[0].pageX;
+					if ((this._tX <= this._tMin && diff < 0) || (this._tX >= this._tMax && diff > 0))
+						return;
+					this._tX += (diff * Math.abs(this._lastX - this._initX) * 0.05);
+					if (this._tX < this._tMin) this._tX = this._tMin;
+					if (this._tX > this._tMax) this._tX = this._tMax;
+					this._scaleAm.translateX(this._tX).step();
+					this.scaleAm = this._scaleAm.export();
+				}
+				// #endif
+			}
+			// #endif
+		}
+	}
+</script>
+
+<style>
+	@keyframes show {
+		0% {
+			opacity: 0
+		}
+
+		100% {
+			opacity: 1;
+		}
+	}
+
+	/* #ifdef MP-WEIXIN */
+	:host {
+		display: block;
+		overflow: scroll;
+		-webkit-overflow-scrolling: touch;
+	}
+
+	/* #endif */
+</style>

+ 102 - 0
components/jyf-parser/libs/CssHandler.js

@@ -0,0 +1,102 @@
+/*
+  解析和匹配 Css 的选择器
+  github:https://github.com/jin-yufeng/Parser
+  docs:https://jin-yufeng.github.io/Parser
+  author:JinYufeng
+  update:2020/03/15
+*/
+var cfg = require('./config.js');
+class CssHandler {
+	constructor(tagStyle) {
+		var styles = Object.assign({}, cfg.userAgentStyles);
+		for (var item in tagStyle)
+			styles[item] = (styles[item] ? styles[item] + ';' : '') + tagStyle[item];
+		this.styles = styles;
+	}
+	getStyle = data => this.styles = new CssParser(data, this.styles).parse();
+	match(name, attrs) {
+		var tmp, matched = (tmp = this.styles[name]) ? tmp + ';' : '';
+		if (attrs.class) {
+			var items = attrs.class.split(' ');
+			for (var i = 0, item; item = items[i]; i++)
+				if (tmp = this.styles['.' + item])
+					matched += tmp + ';';
+		}
+		if (tmp = this.styles['#' + attrs.id])
+			matched += tmp + ';';
+		return matched;
+	}
+}
+module.exports = CssHandler;
+class CssParser {
+	constructor(data, init) {
+		this.data = data;
+		this.floor = 0;
+		this.i = 0;
+		this.list = [];
+		this.res = init;
+		this.state = this.Space;
+	}
+	parse() {
+		for (var c; c = this.data[this.i]; this.i++)
+			this.state(c);
+		return this.res;
+	}
+	section = () => this.data.substring(this.start, this.i);
+	isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+	// 状态机
+	Space(c) {
+		if (c == '.' || c == '#' || this.isLetter(c)) {
+			this.start = this.i;
+			this.state = this.Name;
+		} else if (c == '/' && this.data[this.i + 1] == '*')
+			this.Comment();
+		else if (!cfg.blankChar[c] && c != ';')
+			this.state = this.Ignore;
+	}
+	Comment() {
+		this.i = this.data.indexOf('*/', this.i) + 1;
+		if (!this.i) this.i = this.data.length;
+		this.state = this.Space;
+	}
+	Ignore(c) {
+		if (c == '{') this.floor++;
+		else if (c == '}' && !--this.floor) this.state = this.Space;
+	}
+	Name(c) {
+		if (cfg.blankChar[c]) {
+			this.list.push(this.section());
+			this.state = this.NameSpace;
+		} else if (c == '{') {
+			this.list.push(this.section());
+			this.Content();
+		} else if (c == ',') {
+			this.list.push(this.section());
+			this.Comma();
+		} else if (!this.isLetter(c) && (c < '0' || c > '9') && c != '-' && c != '_')
+			this.state = this.Ignore;
+	}
+	NameSpace(c) {
+		if (c == '{') this.Content();
+		else if (c == ',') this.Comma();
+		else if (!cfg.blankChar[c]) this.state = this.Ignore;
+	}
+	Comma() {
+		while (cfg.blankChar[this.data[++this.i]]);
+		if (this.data[this.i] == '{') this.Content();
+		else {
+			this.start = this.i--;
+			this.state = this.Name;
+		}
+	}
+	Content() {
+		this.start = ++this.i;
+		if ((this.i = this.data.indexOf('}', this.i)) == -1) this.i = this.data.length;
+		var content = this.section();
+		for (var i = 0, item; item = this.list[i++];)
+			if (this.res[item]) this.res[item] += ';' + content;
+			else this.res[item] = content;
+		this.list = [];
+		this.state = this.Space;
+	}
+}

+ 577 - 0
components/jyf-parser/libs/MpHtmlParser.js

@@ -0,0 +1,577 @@
+/*
+  将 html 解析为适用于小程序 rich-text 的 DOM 结构
+  github:https://github.com/jin-yufeng/Parser
+  docs:https://jin-yufeng.github.io/Parser
+  author:JinYufeng
+  update:2020/04/13
+*/
+var cfg = require('./config.js'),
+	blankChar = cfg.blankChar,
+	CssHandler = require('./CssHandler.js'),
+	{
+		screenWidth,
+		system
+	} = wx.getSystemInfoSync();
+// #ifdef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO
+var entities = {
+	lt: '<',
+	gt: '>',
+	amp: '&',
+	quot: '"',
+	apos: "'",
+	nbsp: '\xA0',
+	ensp: '\u2002',
+	emsp: '\u2003',
+	ndash: '–',
+	mdash: '—',
+	middot: '·',
+	lsquo: '‘',
+	rsquo: '’',
+	ldquo: '“',
+	rdquo: '”',
+	bull: '•',
+	hellip: '…',
+	permil: '‰',
+	copy: '©',
+	reg: '®',
+	trade: '™',
+	times: '×',
+	divide: '÷',
+	cent: '¢',
+	pound: '£',
+	yen: '¥',
+	euro: '€',
+	sect: '§'
+};
+// #endif
+var emoji; // emoji 补丁包 https://jin-yufeng.github.io/Parser/#/instructions?id=emoji
+class MpHtmlParser {
+	constructor(data, options = {}) {
+		this.attrs = {};
+		this.compress = options.compress;
+		this.CssHandler = new CssHandler(options.tagStyle, screenWidth);
+		this.data = data;
+		this.domain = options.domain;
+		this.DOM = [];
+		this.i = this.start = this.audioNum = this.imgNum = this.videoNum = 0;
+		this.protocol = this.domain && this.domain.includes('://') ? this.domain.split('://')[0] : '';
+		this.state = this.Text;
+		this.STACK = [];
+		this.useAnchor = options.useAnchor;
+		this.xml = options.xml;
+	}
+	parse() {
+		if (emoji) this.data = emoji.parseEmoji(this.data);
+		for (var c; c = this.data[this.i]; this.i++)
+			this.state(c);
+		if (this.state == this.Text) this.setText();
+		while (this.STACK.length) this.popNode(this.STACK.pop());
+		// #ifdef MP-BAIDU || MP-TOUTIAO
+		// 将顶层标签的一些样式提取出来给 rich-text
+		(function f(ns) {
+			for (var i = ns.length, n; n = ns[--i];) {
+				if (n.type == 'text') continue;
+				if (!n.c) {
+					var style = n.attrs.style;
+					if (style) {
+						var j, k, res;
+						if ((j = style.indexOf('display')) != -1)
+							res = style.substring(j, (k = style.indexOf(';', j)) == -1 ? style.length : k);
+						if ((j = style.indexOf('float')) != -1)
+							res += ';' + style.substring(j, (k = style.indexOf(';', j)) == -1 ? style.length : k);
+						n.attrs.contain = res;
+					}
+				} else f(n.children);
+			}
+		})(this.DOM);
+		// #endif
+		if (this.DOM.length) {
+			this.DOM[0].PoweredBy = 'Parser';
+			if (this.title) this.DOM[0].title = this.title;
+		}
+		return this.DOM;
+	}
+	// 设置属性
+	setAttr() {
+		var name = this.getName(this.attrName);
+		if (cfg.trustAttrs[name]) {
+			if (!this.attrVal) {
+				if (cfg.boolAttrs[name]) this.attrs[name] = 'T';
+			} else if (name == 'src') this.attrs[name] = this.getUrl(this.attrVal.replace(/&amp;/g, '&'));
+			else this.attrs[name] = this.attrVal;
+		}
+		this.attrVal = '';
+		while (blankChar[this.data[this.i]]) this.i++;
+		if (this.isClose()) this.setNode();
+		else {
+			this.start = this.i;
+			this.state = this.AttrName;
+		}
+	}
+	// 设置文本节点
+	setText() {
+		var back, text = this.section();
+		if (!text) return;
+		text = (cfg.onText && cfg.onText(text, () => back = true)) || text;
+		if (back) {
+			this.data = this.data.substr(0, this.start) + text + this.data.substr(this.i);
+			let j = this.start + text.length;
+			for (this.i = this.start; this.i < j; this.i++) this.state(this.data[this.i]);
+			return;
+		}
+		if (!this.pre) {
+			// 合并空白符
+			var tmp = [];
+			for (let i = text.length, c; c = text[--i];)
+				if (!blankChar[c] || (!blankChar[tmp[0]] && (c = ' '))) tmp.unshift(c);
+			text = tmp.join('');
+			if (text == ' ') return;
+		}
+		// 处理实体
+		var siblings = this.siblings(),
+			i = -1,
+			j, en;
+		while (1) {
+			if ((i = text.indexOf('&', i + 1)) == -1) break;
+			if ((j = text.indexOf(';', i + 2)) == -1) break;
+			if (text[i + 1] == '#') {
+				en = parseInt((text[i + 2] == 'x' ? '0' : '') + text.substring(i + 2, j));
+				if (!isNaN(en)) text = text.substr(0, i) + String.fromCharCode(en) + text.substring(j + 1);
+			} else {
+				en = text.substring(i + 1, j);
+				// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
+				if (en == 'nbsp') text = text.substr(0, i) + '\xA0' + text.substr(j + 1); // 解决 &nbsp; 失效
+				else if (en != 'lt' && en != 'gt' && en != 'amp' && en != 'ensp' && en != 'emsp' && en != 'quot' && en != 'apos') {
+					i && siblings.push({
+						type: 'text',
+						text: text.substr(0, i)
+					})
+					siblings.push({
+						type: 'text',
+						text: `&${en};`,
+						en: 1
+					})
+					text = text.substr(j + 1);
+					i = -1;
+				}
+				// #endif
+				// #ifdef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO
+				if (entities[en]) text = text.substr(0, i) + entities[en] + text.substr(j + 1);
+				// #endif
+			}
+		}
+		text && siblings.push({
+			type: 'text',
+			text
+		})
+	}
+	// 设置元素节点
+	setNode() {
+		var node = {
+				name: this.tagName.toLowerCase(),
+				attrs: this.attrs
+			},
+			close = cfg.selfClosingTags[node.name] || (this.xml && this.data[this.i] == '/');
+		this.attrs = {};
+		if (!cfg.ignoreTags[node.name]) {
+			this.matchAttr(node);
+			if (!close) {
+				node.children = [];
+				if (node.name == 'pre' && cfg.highlight) {
+					this.remove(node);
+					this.pre = node.pre = true;
+				}
+				this.siblings().push(node);
+				this.STACK.push(node);
+			} else if (!cfg.filter || cfg.filter(node, this) != false)
+				this.siblings().push(node);
+		} else {
+			if (!close) this.remove(node);
+			else if (node.name == 'source') {
+				var parent = this.STACK[this.STACK.length - 1],
+					attrs = node.attrs;
+				if (parent && attrs.src)
+					if (parent.name == 'video' || parent.name == 'audio')
+						parent.attrs.source.push(attrs.src);
+					else {
+						var i, media = attrs.media;
+						if (parent.name == 'picture' && !parent.attrs.src && !(attrs.src.indexOf('.webp') && system.includes('iOS')) &&
+							(!media || (media.includes('px') &&
+								(((i = media.indexOf('min-width')) != -1 && (i = media.indexOf(':', i + 8)) != -1 && screenWidth > parseInt(
+										media.substr(i + 1))) ||
+									((i = media.indexOf('max-width')) != -1 && (i = media.indexOf(':', i + 8)) != -1 && screenWidth < parseInt(
+										media.substr(i + 1)))))))
+							parent.attrs.src = attrs.src;
+					}
+			} else if (node.name == 'base' && !this.domain) this.domain = node.attrs.href;
+		}
+		if (this.data[this.i] == '/') this.i++;
+		this.start = this.i + 1;
+		this.state = this.Text;
+	}
+	// 移除标签
+	remove(node) {
+		var name = node.name,
+			j = this.i;
+		while (1) {
+			if ((this.i = this.data.indexOf('</', this.i + 1)) == -1) {
+				if (name == 'pre' || name == 'svg') this.i = j;
+				else this.i = this.data.length;
+				return;
+			}
+			this.start = (this.i += 2);
+			while (!blankChar[this.data[this.i]] && !this.isClose()) this.i++;
+			if (this.getName(this.section()) == name) {
+				// 代码块高亮
+				if (name == 'pre') {
+					this.data = this.data.substr(0, j + 1) + cfg.highlight(this.data.substring(j + 1, this.i - 5), node.attrs) +
+						this.data.substr(this.i - 5);
+					return this.i = j;
+				} else if (name == 'style')
+					this.CssHandler.getStyle(this.data.substring(j + 1, this.i - 7));
+				else if (name == 'title')
+					this.title = this.data.substring(j + 1, this.i - 7);
+				if ((this.i = this.data.indexOf('>', this.i)) == -1) this.i = this.data.length;
+				// 处理 svg
+				if (name == 'svg') {
+					var src = this.data.substring(j, this.i + 1);
+					if (!node.attrs.xmlns) src = ' xmlns="http://www.w3.org/2000/svg"' + src;
+					var i = j;
+					while (this.data[j] != '<') j--;
+					src = this.data.substring(j, i) + src;
+					var parent = this.STACK[this.STACK.length - 1];
+					if (node.attrs.width == '100%' && parent && (parent.attrs.style || '').includes('inline'))
+						parent.attrs.style = 'width:300px;max-width:100%;' + parent.attrs.style;
+					this.siblings().push({
+						name: 'img',
+						attrs: {
+							src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
+							ignore: 'T'
+						}
+					})
+				}
+				return;
+			}
+		}
+	}
+	// 处理属性
+	matchAttr(node) {
+		var attrs = node.attrs,
+			style = this.CssHandler.match(node.name, attrs, node) + (attrs.style || ''),
+			styleObj = {};
+		if (attrs.id) {
+			if (this.compress & 1) attrs.id = void 0;
+			else if (this.useAnchor) this.bubble();
+		}
+		if ((this.compress & 2) && attrs.class) attrs.class = void 0;
+		switch (node.name) {
+			case 'img':
+				if (attrs['data-src']) {
+					attrs.src = attrs.src || attrs['data-src'];
+					attrs['data-src'] = void 0;
+				}
+				if (attrs.src && !attrs.ignore) {
+					if (this.bubble()) attrs.i = (this.imgNum++).toString();
+					else attrs.ignore = 'T';
+				}
+				break;
+			case 'a':
+			case 'ad':
+			// #ifdef APP-PLUS
+			case 'iframe':
+			case 'embed':
+			// #endif
+				this.bubble();
+				break;
+			case 'font':
+				if (attrs.color) {
+					styleObj['color'] = attrs.color;
+					attrs.color = void 0;
+				}
+				if (attrs.face) {
+					styleObj['font-family'] = attrs.face;
+					attrs.face = void 0;
+				}
+				if (attrs.size) {
+					var size = parseInt(attrs.size);
+					if (size < 1) size = 1;
+					else if (size > 7) size = 7;
+					var map = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];
+					styleObj['font-size'] = map[size - 1];
+					attrs.size = void 0;
+				}
+				break;
+			case 'video':
+			case 'audio':
+				if (!attrs.id) attrs.id = node.name + (++this[`${node.name}Num`]);
+				else this[`${node.name}Num`]++;
+				if (node.name == 'video') {
+					if (attrs.width) {
+						style = `width:${parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')};${style}`;
+						attrs.width = void 0;
+					}
+					if (attrs.height) {
+						style = `height:${parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')};${style}`;
+						attrs.height = void 0;
+					}
+					if (this.videoNum > 3) node.lazyLoad = true;
+				}
+				attrs.source = [];
+				if (attrs.src) attrs.source.push(attrs.src);
+				if (!attrs.controls && !attrs.autoplay)
+					console.warn(`存在没有 controls 属性的 ${node.name} 标签,可能导致无法播放`, node);
+				this.bubble();
+				break;
+			case 'td':
+			case 'th':
+				if (attrs.colspan || attrs.rowspan)
+					for (var k = this.STACK.length, item; item = this.STACK[--k];)
+						if (item.name == 'table') {
+							item.c = void 0;
+							break;
+						}
+		}
+		if (attrs.align) {
+			styleObj['text-align'] = attrs.align;
+			attrs.align = void 0;
+		}
+		// 压缩 style
+		var styles = style.replace(/&quot;/g, '"').replace(/&amp;/g, '&').split(';');
+		style = '';
+		for (var i = 0, len = styles.length; i < len; i++) {
+			var info = styles[i].split(':');
+			if (info.length < 2) continue;
+			let key = info[0].trim().toLowerCase(),
+				value = info.slice(1).join(':').trim();
+			if (value.includes('-webkit') || value.includes('-moz') || value.includes('-ms') || value.includes('-o') || value
+				.includes(
+					'safe'))
+				style += `;${key}:${value}`;
+			else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import'))
+				styleObj[key] = value;
+		}
+		if (node.name == 'img' && parseInt(styleObj.width || attrs.width) > screenWidth)
+			styleObj.height = 'auto';
+		for (var key in styleObj) {
+			var value = styleObj[key];
+			if (key.includes('flex') || key == 'order' || key == 'self-align') node.c = 1;
+			// 填充链接
+			if (value.includes('url')) {
+				var j = value.indexOf('(');
+				if (j++ != -1) {
+					while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) j++;
+					value = value.substr(0, j) + this.getUrl(value.substr(j));
+				}
+			}
+			// 转换 rpx
+			else if (value.includes('rpx'))
+				value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * screenWidth / 750 + 'px');
+			else if (key == 'white-space' && value.includes('pre'))
+				this.pre = node.pre = true;
+			style += `;${key}:${value}`;
+		}
+		style = style.substr(1);
+		if (style) attrs.style = style;
+	}
+	// 节点出栈处理
+	popNode(node) {
+		// 空白符处理
+		if (node.pre) {
+			node.pre = this.pre = void 0;
+			for (let i = this.STACK.length; i--;)
+				if (this.STACK[i].pre)
+					this.pre = true;
+		}
+		if (node.name == 'head' || (cfg.filter && cfg.filter(node, this) == false))
+			return this.siblings().pop();
+		var attrs = node.attrs;
+		// 替换一些标签名
+		if (node.name == 'picture') {
+			node.name = 'img';
+			if (!attrs.src && (node.children[0] || '').name == 'img')
+				attrs.src = node.children[0].attrs.src;
+			if (attrs.src && !attrs.ignore)
+				attrs.i = (this.imgNum++).toString();
+			return node.children = void 0;
+		}
+		if (cfg.blockTags[node.name]) node.name = 'div';
+		else if (!cfg.trustTags[node.name]) node.name = 'span';
+		// 处理列表
+		if (node.c) {
+			if (node.name == 'ul') {
+				var floor = 1;
+				for (let i = this.STACK.length; i--;)
+					if (this.STACK[i].name == 'ul') floor++;
+				if (floor != 1)
+					for (let i = node.children.length; i--;)
+						node.children[i].floor = floor;
+			} else if (node.name == 'ol') {
+				for (let i = 0, num = 1, child; child = node.children[i++];)
+					if (child.name == 'li') {
+						child.type = 'ol';
+						child.num = ((num, type) => {
+							if (type == 'a') return String.fromCharCode(97 + (num - 1) % 26);
+							if (type == 'A') return String.fromCharCode(65 + (num - 1) % 26);
+							if (type == 'i' || type == 'I') {
+								num = (num - 1) % 99 + 1;
+								var one = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
+									ten = ['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],
+									res = (ten[Math.floor(num / 10) - 1] || '') + (one[num % 10 - 1] || '');
+								if (type == 'i') return res.toLowerCase();
+								return res;
+							}
+							return num;
+						})(num++, attrs.type) + '.';
+					}
+			}
+		}
+		// 处理表格的边框
+		if (node.name == 'table') {
+			var padding = attrs.cellpadding,
+				spacing = attrs.cellspacing,
+				border = attrs.border;
+			if (node.c) {
+				this.bubble();
+				if (!padding) padding = 2;
+				if (!spacing) spacing = 2;
+			}
+			if (border) attrs.style = `border:${border}px solid gray;${attrs.style || ''}`;
+			if (spacing) attrs.style = `border-spacing:${spacing}px;${attrs.style || ''}`;
+			if (border || padding)
+				(function f(ns) {
+					for (var i = 0, n; n = ns[i]; i++) {
+						if (n.name == 'th' || n.name == 'td') {
+							if (border) n.attrs.style = `border:${border}px solid gray;${n.attrs.style}`;
+							if (padding) n.attrs.style = `padding:${padding}px;${n.attrs.style}`;
+						} else f(n.children || []);
+					}
+				})(node.children)
+		}
+		this.CssHandler.pop && this.CssHandler.pop(node);
+		// 自动压缩
+		if (node.name == 'div' && !Object.keys(attrs).length) {
+			var siblings = this.siblings();
+			if (node.children.length == 1 && node.children[0].name == 'div')
+				siblings[siblings.length - 1] = node.children[0];
+		}
+	}
+	// 工具函数
+	bubble() {
+		for (var i = this.STACK.length, item; item = this.STACK[--i];) {
+			if (cfg.richOnlyTags[item.name]) {
+				if (item.name == 'table' && !Object.hasOwnProperty.call(item, 'c')) item.c = 1;
+				return false;
+			}
+			item.c = 1;
+		}
+		return true;
+	}
+	getName = val => this.xml ? val : val.toLowerCase();
+	getUrl(url) {
+		if (url[0] == '/') {
+			if (url[1] == '/') url = this.protocol + ':' + url;
+			else if (this.domain) url = this.domain + url;
+		} else if (this.domain && url.indexOf('data:') != 0 && !url.includes('://'))
+			url = this.domain + '/' + url;
+		return url;
+	}
+	isClose = () => this.data[this.i] == '>' || (this.data[this.i] == '/' && this.data[this.i + 1] == '>');
+	section = () => this.data.substring(this.start, this.i);
+	siblings = () => this.STACK.length ? this.STACK[this.STACK.length - 1].children : this.DOM;
+	// 状态机
+	Text(c) {
+		if (c == '<') {
+			var next = this.data[this.i + 1],
+				isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+			if (isLetter(next)) {
+				this.setText();
+				this.start = this.i + 1;
+				this.state = this.TagName;
+			} else if (next == '/') {
+				this.setText();
+				if (isLetter(this.data[++this.i + 1])) {
+					this.start = this.i + 1;
+					this.state = this.EndTag;
+				} else
+					this.Comment();
+			} else if (next == '!') {
+				this.setText();
+				this.Comment();
+			}
+		}
+	}
+	Comment() {
+		var key;
+		if (this.data.substring(this.i + 2, this.i + 4) == '--') key = '-->';
+		else if (this.data.substring(this.i + 2, this.i + 9) == '[CDATA[') key = ']]>';
+		else key = '>';
+		if ((this.i = this.data.indexOf(key, this.i + 2)) == -1) this.i = this.data.length;
+		else this.i += key.length - 1;
+		this.start = this.i + 1;
+		this.state = this.Text;
+	}
+	TagName(c) {
+		if (blankChar[c]) {
+			this.tagName = this.section();
+			while (blankChar[this.data[this.i]]) this.i++;
+			if (this.isClose()) this.setNode();
+			else {
+				this.start = this.i;
+				this.state = this.AttrName;
+			}
+		} else if (this.isClose()) {
+			this.tagName = this.section();
+			this.setNode();
+		}
+	}
+	AttrName(c) {
+		var blank = blankChar[c];
+		if (blank) {
+			this.attrName = this.section();
+			c = this.data[this.i];
+		}
+		if (c == '=') {
+			if (!blank) this.attrName = this.section();
+			while (blankChar[this.data[++this.i]]);
+			this.start = this.i--;
+			this.state = this.AttrValue;
+		} else if (blank) this.setAttr();
+		else if (this.isClose()) {
+			this.attrName = this.section();
+			this.setAttr();
+		}
+	}
+	AttrValue(c) {
+		if (c == '"' || c == "'") {
+			this.start++;
+			if ((this.i = this.data.indexOf(c, this.i + 1)) == -1) return this.i = this.data.length;
+			this.attrVal = this.section();
+			this.i++;
+		} else {
+			for (; !blankChar[this.data[this.i]] && !this.isClose(); this.i++);
+			this.attrVal = this.section();
+		}
+		this.setAttr();
+	}
+	EndTag(c) {
+		if (blankChar[c] || c == '>' || c == '/') {
+			var name = this.getName(this.section());
+			for (var i = this.STACK.length; i--;)
+				if (this.STACK[i].name == name) break;
+			if (i != -1) {
+				var node;
+				while ((node = this.STACK.pop()).name != name);
+				this.popNode(node);
+			} else if (name == 'p' || name == 'br')
+				this.siblings().push({
+					name,
+					attrs: {}
+				});
+			this.i = this.data.indexOf('>', this.i);
+			this.start = this.i + 1;
+			if (this.i == -1) this.i = this.data.length;
+			else this.state = this.Text;
+		}
+	}
+}
+module.exports = MpHtmlParser;

+ 80 - 0
components/jyf-parser/libs/config.js

@@ -0,0 +1,80 @@
+/* 配置文件 */
+// #ifdef MP-WEIXIN
+const canIUse = wx.canIUse('editor'); // 高基础库标识,用于兼容
+// #endif
+module.exports = {
+	// 过滤器函数
+	filter: null,
+	// 代码高亮函数
+	highlight: null,
+	// 文本处理函数
+	onText: null,
+	blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'),
+	// 块级标签,将被转为 div
+	blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,section' + (
+		// #ifdef MP-WEIXIN
+		canIUse ? '' :
+		// #endif
+		',pre')),
+	// 将被移除的标签
+	ignoreTags: makeMap(
+		'area,base,basefont,canvas,command,frame,input,isindex,keygen,link,map,meta,param,script,source,style,svg,textarea,title,track,use,wbr'
+		// #ifdef MP-WEIXIN
+		+ (canIUse ? ',rp' : '')
+		// #endif
+		// #ifndef APP-PLUS
+		+ ',embed,iframe'
+		// #endif
+	),
+	// 只能被 rich-text 显示的标签
+	richOnlyTags: makeMap('a,colgroup,fieldset,legend,picture,table'
+		// #ifdef MP-WEIXIN
+		+ (canIUse ? ',bdi,bdo,caption,rt,ruby' : '')
+		// #endif
+	),
+	// 自闭合的标签
+	selfClosingTags: makeMap(
+		'area,base,basefont,br,col,circle,ellipse,embed,frame,hr,img,input,isindex,keygen,line,link,meta,param,path,polygon,rect,source,track,use,wbr'
+	),
+	// 信任的属性
+	trustAttrs: makeMap(
+		'align,alt,app-id,author,autoplay,border,cellpadding,cellspacing,class,color,colspan,controls,data-src,dir,face,height,href,id,ignore,loop,media,muted,name,path,poster,rowspan,size,span,src,start,style,type,unit-id,width,xmlns'
+	),
+	// bool 型的属性
+	boolAttrs: makeMap('autoplay,controls,ignore,loop,muted'),
+	// 信任的标签
+	trustTags: makeMap(
+		'a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'
+		// #ifdef MP-WEIXIN
+		+ (canIUse ? ',bdi,bdo,caption,pre,rt,ruby' : '')
+		// #endif
+		// #ifdef APP-PLUS
+		+ ',embed,iframe'
+		// #endif
+	),
+	// 默认的标签样式
+	userAgentStyles: {
+		address: 'font-style:italic',
+		big: 'display:inline;font-size:1.2em',
+		blockquote: 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px',
+		caption: 'display:table-caption;text-align:center',
+		center: 'text-align:center',
+		cite: 'font-style:italic',
+		dd: 'margin-left:40px',
+		img: 'max-width:100%',
+		mark: 'background-color:yellow',
+		picture: 'max-width:100%',
+		pre: 'font-family:monospace;white-space:pre;overflow:scroll',
+		s: 'text-decoration:line-through',
+		small: 'display:inline;font-size:0.8em',
+		u: 'text-decoration:underline'
+	}
+}
+
+function makeMap(maprichee55text9oppplugin) {
+	var map = {},
+		list = maprichee55text9oppplugin.split(',');
+	for (var i = list.length; i--;)
+		map[list[i]] = true;
+	return map;
+}

+ 35 - 0
components/jyf-parser/libs/handler.sjs

@@ -0,0 +1,35 @@
+var inlineTags = {
+	abbr: 1,
+	b: 1,
+	big: 1,
+	code: 1,
+	del: 1,
+	em: 1,
+	i: 1,
+	ins: 1,
+	label: 1,
+	q: 1,
+	small: 1,
+	span: 1,
+	strong: 1
+}
+export default {
+	// 从顶层标签的样式中取出一些给 rich-text
+	getStyle: function(style) {
+		if (style) {
+			var i, j, res = '';
+			if ((i = style.indexOf('display')) != -1)
+				res = style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
+			if ((i = style.indexOf('float')) != -1)
+				res += ';' + style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
+			return res;
+		}
+	},
+	getNode: function(item) {
+		return [item];
+	},
+	// 是否通过 rich-text 显示
+	useRichText: function(item) {
+		return !item.c && !inlineTags[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1;
+	}
+}

+ 44 - 0
components/jyf-parser/libs/handler.wxs

@@ -0,0 +1,44 @@
+var inlineTags = {
+	abbr: 1,
+	b: 1,
+	big: 1,
+	code: 1,
+	del: 1,
+	em: 1,
+	i: 1,
+	ins: 1,
+	label: 1,
+	q: 1,
+	small: 1,
+	span: 1,
+	strong: 1
+}
+module.exports = {
+	// 从顶层标签的样式中取出一些给 rich-text
+	getStyle: function(style) {
+		if (style) {
+			var i, j, res = '';
+			if ((i = style.indexOf('display')) != -1)
+				res = style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
+			if ((i = style.indexOf('float')) != -1)
+				res += ';' + style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
+			return res;
+		}
+	},
+	// 处理懒加载
+	getNode: function(item, imgLoad) {
+		if (!imgLoad && item.attrs.i != '0') {
+			var img = {
+				name: 'img',
+				attrs: JSON.parse(JSON.stringify(item.attrs))
+			}
+			delete img.attrs.src;
+			img.attrs.style += ';width:20px;height:20px';
+			return [img];
+		} else return [item];
+	},
+	// 是否通过 rich-text 显示
+	useRichText: function(item) {
+		return !item.c && !inlineTags[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1;
+	}
+}

+ 476 - 0
components/jyf-parser/libs/trees.vue

@@ -0,0 +1,476 @@
+<!--
+  trees 递归显示组件
+  github:https://github.com/jin-yufeng/Parser 
+  docs:https://jin-yufeng.github.io/Parser
+  插件市场:https://ext.dcloud.net.cn/plugin?id=805
+  author:JinYufeng
+  update:2020/04/13
+-->
+<template>
+	<view class="interlayer">
+		<block v-for="(n, index) in nodes" v-bind:key="index">
+			<!--图片-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
+			<rich-text v-if="n.name=='img'" :id="n.attrs.id" class="_img" :style="''+handler.getStyle(n.attrs.style)" :nodes="handler.getNode(n,!lazyLoad||imgLoad)"
+			 :data-attrs="n.attrs" @tap="imgtap" @longpress="imglongtap" />
+			<!--#endif-->
+			<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
+			<rich-text v-if="n.name=='img'" :id="n.attrs.id" class="_img" :style="n.attrs.contain" :nodes='[n]' :data-attrs="n.attrs"
+			 @tap="imgtap" @longpress="imglongtap" />
+			<!--#endif-->
+			<!--文本-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || APP-PLUS-->
+			<rich-text v-else-if="n.decode" class="_entity" :nodes="[n]"></rich-text>
+			<!--#endif-->
+			<text v-else-if="n.type=='text'" decode>{{n.text}}</text>
+			<text v-else-if="n.name=='br'">\n</text>
+			<!--视频-->
+			<view v-else-if="n.name=='video'">
+				<view v-if="(!loadVideo||n.lazyLoad)&&!(controls[n.attrs.id]&&controls[n.attrs.id].play)" :id="n.attrs.id" :class="'_video '+(n.attrs.class||'')"
+				 :style="n.attrs.style" @tap="_loadVideo" />
+				<video v-else :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||(controls[n.attrs.id]&&controls[n.attrs.id].play)"
+				 :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[(controls[n.attrs.id]&&controls[n.attrs.id].index)||0]"
+				 :unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" data-from="video" data-source="source" @error="error" @play="play" />
+			</view>
+			<!--音频-->
+			<audio v-else-if="n.name=='audio'" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :autoplay="n.attrs.autoplay"
+			 :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.attrs.source[(controls[n.attrs.id]&&controls[n.attrs.id].index)||0]"
+			 :data-id="n.attrs.id" data-from="audio" data-source="source" @error="error" @play="play" />
+			<!--链接-->
+			<view v-else-if="n.name=='a'" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style"
+			 :data-attrs="n.attrs" @tap="linkpress">
+				<trees class="_span" :nodes="n.children" />
+			</view>
+			<!--广告(按需打开注释)-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO-->
+			<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :unit-id="n.attrs['unit-id']"
+			 data-from="ad" @error="error" />-->
+			<!--#endif-->
+			<!--#ifdef MP-BAIDU-->
+			<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :appid="n.attrs.appid"
+			 :apid="n.attrs.apid" :type="n.attrs.type" data-from="ad" @error="error" />-->
+			<!--#endif-->
+			<!--#ifdef APP-PLUS-->
+			<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :adpid="n.attrs.adpid"
+			 data-from="ad" @error="error" />-->
+			<!--#endif-->
+			<!--列表-->
+			<view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex'">
+				<view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view>
+				<view v-else class="_ul-bef">
+					<view v-if="n.floor%3==0" class="_ul-p1">█</view>
+					<view v-else-if="n.floor%3==2" class="_ul-p2" />
+					<view v-else class="_ul-p1" style="border-radius:50%">█</view>
+				</view>
+				<!--#ifdef MP-ALIPAY-->
+				<view class="_li">
+					<trees :nodes="n.children" />
+				</view>
+				<!--#endif-->
+				<!--#ifndef MP-ALIPAY-->
+				<trees class="_li" :nodes="n.children" :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
+				<!--#endif-->
+			</view>
+			<!--表格-->
+			<view v-else-if="n.name=='table'&&n.c" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:table'">
+				<view v-for="(tbody, i) in n.children" v-bind:key="i" :class="tbody.attrs.class" :style="(tbody.attrs.style||'')+(tbody.name[0]=='t'?';display:table-'+(tbody.name=='tr'?'row':'row-group'):'')">
+					<view v-for="(tr, j) in tbody.children" v-bind:key="j" :class="tr.attrs.class" :style="(tr.attrs.style||'')+(tr.name[0]=='t'?';display:table-'+(tr.name=='tr'?'row':'cell'):'')">
+						<trees v-if="tr.name=='td'" :nodes="tr.children" :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
+						<block v-else>
+							<!--#ifdef MP-ALIPAY-->
+							<view v-for="(td, k) in tr.children" v-bind:key="k" :class="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')">
+								<trees :nodes="td.children" />
+							</view>
+							<!--#endif-->
+							<!--#ifndef MP-ALIPAY-->
+							<trees v-for="(td, k) in tr.children" v-bind:key="k" :class="td.attrs.class" :style="(td.attrs.style||'')+(td.name[0]=='t'?';display:table-'+(td.name=='tr'?'row':'cell'):'')"
+							 :nodes="td.children" :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
+							<!--#endif-->
+						</block>
+					</view>
+				</view>
+			</view>
+			<!--#ifdef APP-PLUS-->
+			<iframe v-else-if="n.name=='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder"
+			 :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
+			<embed v-else-if="n.name=='embed'" :style="n.attrs.style" :width="n.attrs.width" :height="n.attrs.height" :src="n.attrs.src" />
+			<!--#endif-->
+			<!--富文本-->
+			<!--#ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY || APP-PLUS-->
+			<rich-text v-else-if="handler.useRichText(n)" :id="n.attrs.id" :class="'_p __'+n.name" :nodes="[n]" />
+			<!--#endif-->
+			<!--#ifdef MP-BAIDU || MP-TOUTIAO-->
+			<rich-text v-else-if="!(n.c||n.continue)" :id="n.attrs.id" :class="_p" :style="n.attrs.contain" :nodes="[n]" />
+			<!--#endif-->
+			<!--#ifdef MP-ALIPAY-->
+			<view v-else :id="n.attrs.id" :class="'_'+n.name+' '+(n.attrs.class||'')" :style="n.attrs.style">
+				<trees :nodes="n.children" />
+			</view>
+			<!--#endif-->
+			<!--#ifndef MP-ALIPAY-->
+			<trees v-else :class="(n.attrs.id||'')+' _'+n.name+' '+(n.attrs.class||'')" :style="n.attrs.style" :nodes="n.children"
+			 :lazyLoad="lazyLoad" :loadVideo="loadVideo" />
+			<!--#endif-->
+		</block>
+	</view>
+</template>
+<script module="handler" lang="wxs" src="./handler.wxs"></script>
+<script module="handler" lang="sjs" src="./handler.sjs"></script>
+<script>
+	global.Parser = {};
+	import trees from './trees'
+	export default {
+		components: {
+			trees
+		},
+		name: 'trees',
+		data() {
+			return {
+				controls: {},
+				// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
+				imgLoad: false,
+				// #endif
+				// #ifndef APP-PLUS
+				loadVideo: true
+				// #endif
+			}
+		},
+		props: {
+			nodes: Array,
+			// #ifdef MP-WEIXIN || MP-QQ || H5 || APP-PLUS
+			lazyLoad: Boolean,
+			// #endif
+			// #ifdef APP-PLUS
+			loadVideo: Boolean
+			// #endif
+		},
+		mounted() {
+			// 获取顶层组件
+			this.top = this.$parent;
+			while (this.top.$options.name != 'parser') {
+				if (this.top.top) {
+					this.top = this.top.top;
+					break;
+				}
+				this.top = this.top.$parent;
+			}
+		},
+		// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS
+		beforeDestroy() {
+			if (this.observer)
+				this.observer.disconnect();
+		},
+		// #endif
+		methods: {
+			// #ifndef MP-ALIPAY
+			play(e) {
+				if (this.top.videoContexts.length > 1 && this.top.autopause)
+					for (var i = this.top.videoContexts.length; i--;)
+						if (this.top.videoContexts[i].id != e.currentTarget.dataset.id)
+							this.top.videoContexts[i].pause();
+			},
+			// #endif
+			imgtap(e) {
+				var attrs = e.currentTarget.dataset.attrs;
+				if (!attrs.ignore) {
+					var preview = true, data = {
+						id: e.target.id,
+						src: attrs.src,
+						ignore: () => preview = false
+					};
+					global.Parser.onImgtap && global.Parser.onImgtap(data);
+					this.top.$emit('imgtap', data);
+					if (preview) {
+						var urls = this.top.imgList,
+							current = urls[attrs.i] ? parseInt(attrs.i) : (urls = [attrs.src], 0);
+						uni.previewImage({
+							current,
+							urls
+						})
+					}
+				}
+			},
+			imglongtap(e) {
+				var attrs = e.item.dataset.attrs;
+				if (!attrs.ignore)
+					this.top.$emit('imglongtap', {
+						id: e.target.id,
+						src: attrs.src
+					})
+			},
+			linkpress(e) {
+				var jump = true,
+					attrs = e.currentTarget.dataset.attrs;
+				attrs.ignore = () => jump = false;
+				global.Parser.onLinkpress && global.Parser.onLinkpress(attrs);
+				this.top.$emit('linkpress', attrs);
+				if (jump) {
+					// #ifdef MP
+					if (attrs['app-id']) {
+						return uni.navigateToMiniProgram({
+							appId: attrs['app-id'],
+							path: attrs.path
+						})
+					}
+					// #endif
+					if (attrs.href) {
+						if (attrs.href[0] == '#') {
+							if (this.top.useAnchor)
+								this.top.navigateTo({
+									id: attrs.href.substring(1)
+								})
+						} else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0) {
+							// #ifdef APP-PLUS
+							plus.runtime.openWeb(attrs.href);
+							// #endif
+							// #ifndef APP-PLUS
+							uni.setClipboardData({
+								data: attrs.href,
+								success: () =>
+									uni.showToast({
+										title: '链接已复制'
+									})
+							})
+							// #endif
+						} else
+							uni.navigateTo({
+								url: attrs.href
+							})
+					}
+				}
+			},
+			error(e) {
+				var context, target = e.currentTarget,
+					source = target.dataset.from;
+				if (source == 'video' || source == 'audio') {
+					// 加载其他 source
+					var index = this.controls[target.id] ? this.controls[target.id].index + 1 : 1;
+					if (index < target.dataset.source.length)
+						this.$set(this.controls, target.id + '.index', index);
+					if (source == 'video') context = uni.createVideoContext(target.id, this);
+				}
+				this.top && this.top.$emit('error', {
+					source,
+					target,
+					errMsg: e.detail.errMsg,
+					errCode: e.detail.errCode,
+					context
+				});
+			},
+			_loadVideo(e) {
+				this.$set(this.controls, e.currentTarget.id, {
+					play: true,
+					index: 0
+				})
+			}
+		}
+	}
+</script>
+
+<style>
+	/* 在这里引入自定义样式 */
+
+	/* 链接和图片效果 */
+	._a {
+		display: inline;
+		color: #366092;
+		word-break: break-all;
+		padding: 1.5px 0 1.5px 0;
+	}
+
+	._hover {
+		opacity: 0.7;
+		text-decoration: underline;
+	}
+
+	._img {
+		display: inline-block;
+		text-indent: 0;
+	}
+
+	/* #ifdef MP-WEIXIN */
+	:host {
+		display: inline;
+	}
+
+	/* #endif */
+
+	/* #ifdef MP */
+	.interlayer {
+		align-content: inherit;
+		align-items: inherit;
+		display: inherit;
+		flex-direction: inherit;
+		flex-wrap: inherit;
+		justify-content: inherit;
+		width: 100%;
+		white-space: inherit;
+	}
+
+	/* #endif */
+
+	._b,
+	._strong {
+		font-weight: bold;
+	}
+
+	._blockquote,
+	._div,
+	._p,
+	._ol,
+	._ul,
+	._li {
+		display: block;
+	}
+
+	._code {
+		font-family: monospace;
+	}
+
+	._del {
+		text-decoration: line-through;
+	}
+
+	._em,
+	._i {
+		font-style: italic;
+	}
+
+	._h1 {
+		font-size: 2em;
+	}
+
+	._h2 {
+		font-size: 1.5em;
+	}
+
+	._h3 {
+		font-size: 1.17em;
+	}
+
+	._h5 {
+		font-size: 0.83em;
+	}
+
+	._h6 {
+		font-size: 0.67em;
+	}
+
+	._h1,
+	._h2,
+	._h3,
+	._h4,
+	._h5,
+	._h6 {
+		display: block;
+		font-weight: bold;
+	}
+
+	._ins {
+		text-decoration: underline;
+	}
+
+	._li {
+		flex: 1;
+		width: 0;
+	}
+
+	._ol-bef {
+		margin-right: 5px;
+		text-align: right;
+		width: 36px;
+	}
+
+	._ul-bef {
+		line-height: normal;
+		margin: 0 12px 0 23px;
+	}
+
+	._ol-bef,
+	._ul_bef {
+		flex: none;
+		user-select: none;
+	}
+
+	._ul-p1 {
+		display: inline-block;
+		height: 0.3em;
+		line-height: 0.3em;
+		overflow: hidden;
+		width: 0.3em;
+	}
+
+	._ul-p2 {
+		border: 0.05em solid black;
+		border-radius: 50%;
+		display: inline-block;
+		height: 0.23em;
+		width: 0.23em;
+	}
+
+	._q::before {
+		content: '"';
+	}
+
+	._q::after {
+		content: '"';
+	}
+
+	._sub {
+		font-size: smaller;
+		vertical-align: sub;
+	}
+
+	._sup {
+		font-size: smaller;
+		vertical-align: super;
+	}
+
+	/* #ifndef MP-WEIXIN */
+	._abbr,
+	._b,
+	._code,
+	._del,
+	._em,
+	._i,
+	._ins,
+	._label,
+	._q,
+	._span,
+	._strong,
+	._sub,
+	._sup {
+		display: inline;
+	}
+
+	/* #endif */
+
+	/* #ifdef MP-WEIXIN || MP-QQ || MP-ALIPAY */
+	.__bdo,
+	.__bdi,
+	.__ruby,
+	.__rt,
+	._entity {
+		display: inline-block;
+	}
+
+	/* #endif */
+	._video {
+		background-color: black;
+		display: inline-block;
+		height: 225px;
+		position: relative;
+		width: 300px;
+	}
+
+	._video::after {
+		border-color: transparent transparent transparent white;
+		border-style: solid;
+		border-width: 15px 0 15px 30px;
+		content: '';
+		left: 50%;
+		margin: -15px 0 0 -15px;
+		position: absolute;
+		top: 50%;
+	}
+</style>

+ 1356 - 0
components/wangding-pickerAddress/data.js

@@ -0,0 +1,1356 @@
+export default [{
+	"name": "北京市",
+	"city": [{
+		"name": "市辖区",
+		"area": ["东城区", "西城区", "朝阳区", "丰台区", "石景山区", "海淀区", "门头沟区", "房山区", "通州区", "顺义区", "昌平区", "大兴区",
+			"怀柔区", "平谷区", "密云区", "延庆区"
+		]
+	}]
+}, {
+	"name": "天津市",
+	"city": [{
+		"name": "市辖区",
+		"area": ["和平区", "河东区", "河西区", "南开区", "河北区", "红桥区", "东丽区", "西青区", "津南区", "北辰区", "武清区", "宝坻区", "滨海新区",
+			"宁河区", "静海区", "蓟州区"
+		]
+	}]
+}, {
+	"name": "河北省",
+	"city": [{
+		"name": "石家庄市",
+		"area": ["市辖区", "长安区", "桥西区", "新华区", "井陉矿区", "裕华区", "藁城区", "鹿泉区", "栾城区", "井陉县", "正定县", "行唐县", "灵寿县",
+			"高邑县", "深泽县", "赞皇县", "无极县", "平山县", "元氏县", "赵县", "晋州市", "新乐市"
+		]
+	}, {
+		"name": "唐山市",
+		"area": ["市辖区", "路南区", "路北区", "古冶区", "开平区", "丰南区", "丰润区", "曹妃甸区", "滦县", "滦南县", "乐亭县", "迁西县", "玉田县",
+			"遵化市", "迁安市"
+		]
+	}, {
+		"name": "秦皇岛市",
+		"area": ["市辖区", "海港区", "山海关区", "北戴河区", "抚宁区", "青龙满族自治县", "昌黎县", "卢龙县"]
+	}, {
+		"name": "邯郸市",
+		"area": ["市辖区", "邯山区", "丛台区", "复兴区", "峰峰矿区", "邯郸县", "临漳县", "成安县", "大名县", "涉县", "磁县", "肥乡县", "永年县",
+			"邱县", "鸡泽县", "广平县", "馆陶县", "魏县", "曲周县", "武安市"
+		]
+	}, {
+		"name": "邢台市",
+		"area": ["市辖区", "桥东区", "桥西区", "邢台县", "临城县", "内丘县", "柏乡县", "隆尧县", "任县", "南和县", "宁晋县", "巨鹿县", "新河县",
+			"广宗县", "平乡县", "威县", "清河县", "临西县", "南宫市", "沙河市"
+		]
+	}, {
+		"name": "保定市",
+		"area": ["市辖区", "竞秀区", "莲池区", "满城区", "清苑区", "徐水区", "涞水县", "阜平县", "定兴县", "唐县", "高阳县", "容城县", "涞源县",
+			"望都县", "安新县", "易县", "曲阳县", "蠡县", "顺平县", "博野县", "雄县", "涿州市", "安国市", "高碑店市"
+		]
+	}, {
+		"name": "张家口市",
+		"area": ["市辖区", "桥东区", "桥西区", "宣化区", "下花园区", "万全区", "崇礼区", "张北县", "康保县", "沽源县", "尚义县", "蔚县", "阳原县",
+			"怀安县", "怀来县", "涿鹿县", "赤城县"
+		]
+	}, {
+		"name": "承德市",
+		"area": ["市辖区", "双桥区", "双滦区", "鹰手营子矿区", "承德县", "兴隆县", "平泉县", "滦平县", "隆化县", "丰宁满族自治县", "宽城满族自治县",
+			"围场满族蒙古族自治县"
+		]
+	}, {
+		"name": "沧州市",
+		"area": ["市辖区", "新华区", "运河区", "沧县", "青县", "东光县", "海兴县", "盐山县", "肃宁县", "南皮县", "吴桥县", "献县", "孟村回族自治县",
+			"泊头市", "任丘市", "黄骅市", "河间市"
+		]
+	}, {
+		"name": "廊坊市",
+		"area": ["市辖区", "安次区", "广阳区", "固安县", "永清县", "香河县", "大城县", "文安县", "大厂回族自治县", "霸州市", "三河市"]
+	}, {
+		"name": "衡水市",
+		"area": ["市辖区", "桃城区", "冀州区", "枣强县", "武邑县", "武强县", "饶阳县", "安平县", "故城县", "景县", "阜城县", "深州市"]
+	}, {
+		"name": "直辖县",
+		"area": ["定州市", "辛集市"]
+	}]
+}, {
+	"name": "山西省",
+	"city": [{
+		"name": "太原市",
+		"area": ["市辖区", "小店区", "迎泽区", "杏花岭区", "尖草坪区", "万柏林区", "晋源区", "清徐县", "阳曲县", "娄烦县", "古交市"]
+	}, {
+		"name": "大同市",
+		"area": ["市辖区", "城区", "矿区", "南郊区", "新荣区", "阳高县", "天镇县", "广灵县", "灵丘县", "浑源县", "左云县", "大同县"]
+	}, {
+		"name": "阳泉市",
+		"area": ["市辖区", "城区", "矿区", "郊区", "平定县", "盂县"]
+	}, {
+		"name": "长治市",
+		"area": ["市辖区", "城区", "郊区", "长治县", "襄垣县", "屯留县", "平顺县", "黎城县", "壶关县", "长子县", "武乡县", "沁县", "沁源县",
+			"潞城市"
+		]
+	}, {
+		"name": "晋城市",
+		"area": ["市辖区", "城区", "沁水县", "阳城县", "陵川县", "泽州县", "高平市"]
+	}, {
+		"name": "朔州市",
+		"area": ["市辖区", "朔城区", "平鲁区", "山阴县", "应县", "右玉县", "怀仁县"]
+	}, {
+		"name": "晋中市",
+		"area": ["市辖区", "榆次区", "榆社县", "左权县", "和顺县", "昔阳县", "寿阳县", "太谷县", "祁县", "平遥县", "灵石县", "介休市"]
+	}, {
+		"name": "运城市",
+		"area": ["市辖区", "盐湖区", "临猗县", "万荣县", "闻喜县", "稷山县", "新绛县", "绛县", "垣曲县", "夏县", "平陆县", "芮城县", "永济市",
+			"河津市"
+		]
+	}, {
+		"name": "忻州市",
+		"area": ["市辖区", "忻府区", "定襄县", "五台县", "代县", "繁峙县", "宁武县", "静乐县", "神池县", "五寨县", "岢岚县", "河曲县", "保德县",
+			"偏关县", "原平市"
+		]
+	}, {
+		"name": "临汾市",
+		"area": ["市辖区", "尧都区", "曲沃县", "翼城县", "襄汾县", "洪洞县", "古县", "安泽县", "浮山县", "吉县", "乡宁县", "大宁县", "隰县",
+			"永和县", "蒲县", "汾西县", "侯马市", "霍州市"
+		]
+	}, {
+		"name": "吕梁市",
+		"area": ["市辖区", "离石区", "文水县", "交城县", "兴县", "临县", "柳林县", "石楼县", "岚县", "方山县", "中阳县", "交口县", "孝义市",
+			"汾阳市"
+		]
+	}]
+}, {
+	"name": "内蒙古自治区",
+	"city": [{
+		"name": "呼和浩特市",
+		"area": ["市辖区", "新城区", "回民区", "玉泉区", "赛罕区", "土默特左旗", "托克托县", "和林格尔县", "清水河县", "武川县"]
+	}, {
+		"name": "包头市",
+		"area": ["市辖区", "东河区", "昆都仑区", "青山区", "石拐区", "白云鄂博矿区", "九原区", "土默特右旗", "固阳县", "达尔罕茂明安联合旗"]
+	}, {
+		"name": "乌海市",
+		"area": ["市辖区", "海勃湾区", "海南区", "乌达区"]
+	}, {
+		"name": "赤峰市",
+		"area": ["市辖区", "红山区", "元宝山区", "松山区", "阿鲁科尔沁旗", "巴林左旗", "巴林右旗", "林西县", "克什克腾旗", "翁牛特旗", "喀喇沁旗",
+			"宁城县", "敖汉旗"
+		]
+	}, {
+		"name": "通辽市",
+		"area": ["市辖区", "科尔沁区", "科尔沁左翼中旗", "科尔沁左翼后旗", "开鲁县", "库伦旗", "奈曼旗", "扎鲁特旗", "霍林郭勒市"]
+	}, {
+		"name": "鄂尔多斯市",
+		"area": ["市辖区", "东胜区", "康巴什区", "达拉特旗", "准格尔旗", "鄂托克前旗", "鄂托克旗", "杭锦旗", "乌审旗", "伊金霍洛旗"]
+	}, {
+		"name": "呼伦贝尔市",
+		"area": ["市辖区", "海拉尔区", "扎赉诺尔区", "阿荣旗", "莫力达瓦达斡尔族自治旗", "鄂伦春自治旗", "鄂温克族自治旗", "陈巴尔虎旗", "新巴尔虎左旗",
+			"新巴尔虎右旗", "满洲里市", "牙克石市", "扎兰屯市", "额尔古纳市", "根河市"
+		]
+	}, {
+		"name": "巴彦淖尔市",
+		"area": ["市辖区", "临河区", "五原县", "磴口县", "乌拉特前旗", "乌拉特中旗", "乌拉特后旗", "杭锦后旗"]
+	}, {
+		"name": "乌兰察布市",
+		"area": ["市辖区", "集宁区", "卓资县", "化德县", "商都县", "兴和县", "凉城县", "察哈尔右翼前旗", "察哈尔右翼中旗", "察哈尔右翼后旗", "四子王旗",
+			"丰镇市"
+		]
+	}, {
+		"name": "兴安盟",
+		"area": ["乌兰浩特市", "阿尔山市", "科尔沁右翼前旗", "科尔沁右翼中旗", "扎赉特旗", "突泉县"]
+	}, {
+		"name": "锡林郭勒盟",
+		"area": ["二连浩特市", "锡林浩特市", "阿巴嘎旗", "苏尼特左旗", "苏尼特右旗", "东乌珠穆沁旗", "西乌珠穆沁旗", "太仆寺旗", "镶黄旗", "正镶白旗",
+			"正蓝旗", "多伦县"
+		]
+	}, {
+		"name": "阿拉善盟",
+		"area": ["阿拉善左旗", "阿拉善右旗", "额济纳旗"]
+	}]
+}, {
+	"name": "辽宁省",
+	"city": [{
+		"name": "沈阳市",
+		"area": ["市辖区", "和平区", "沈河区", "大东区", "皇姑区", "铁西区", "苏家屯区", "浑南区", "沈北新区", "于洪区", "辽中区", "康平县",
+			"法库县", "新民市"
+		]
+	}, {
+		"name": "大连市",
+		"area": ["市辖区", "中山区", "西岗区", "沙河口区", "甘井子区", "旅顺口区", "金州区", "普兰店区", "长海县", "瓦房店市", "庄河市"]
+	}, {
+		"name": "鞍山市",
+		"area": ["市辖区", "铁东区", "铁西区", "立山区", "千山区", "台安县", "岫岩满族自治县", "海城市"]
+	}, {
+		"name": "抚顺市",
+		"area": ["市辖区", "新抚区", "东洲区", "望花区", "顺城区", "抚顺县", "新宾满族自治县", "清原满族自治县"]
+	}, {
+		"name": "本溪市",
+		"area": ["市辖区", "平山区", "溪湖区", "明山区", "南芬区", "本溪满族自治县", "桓仁满族自治县"]
+	}, {
+		"name": "丹东市",
+		"area": ["市辖区", "元宝区", "振兴区", "振安区", "宽甸满族自治县", "东港市", "凤城市"]
+	}, {
+		"name": "锦州市",
+		"area": ["市辖区", "古塔区", "凌河区", "太和区", "黑山县", "义县", "凌海市", "北镇市"]
+	}, {
+		"name": "营口市",
+		"area": ["市辖区", "站前区", "西市区", "鲅鱼圈区", "老边区", "盖州市", "大石桥市"]
+	}, {
+		"name": "阜新市",
+		"area": ["市辖区", "海州区", "新邱区", "太平区", "清河门区", "细河区", "阜新蒙古族自治县", "彰武县"]
+	}, {
+		"name": "辽阳市",
+		"area": ["市辖区", "白塔区", "文圣区", "宏伟区", "弓长岭区", "太子河区", "辽阳县", "灯塔市"]
+	}, {
+		"name": "盘锦市",
+		"area": ["市辖区", "双台子区", "兴隆台区", "大洼区", "盘山县"]
+	}, {
+		"name": "铁岭市",
+		"area": ["市辖区", "银州区", "清河区", "铁岭县", "西丰县", "昌图县", "调兵山市", "开原市"]
+	}, {
+		"name": "朝阳市",
+		"area": ["市辖区", "双塔区", "龙城区", "朝阳县", "建平县", "喀喇沁左翼蒙古族自治县", "北票市", "凌源市"]
+	}, {
+		"name": "葫芦岛市",
+		"area": ["市辖区", "连山区", "龙港区", "南票区", "绥中县", "建昌县", "兴城市"]
+	}]
+}, {
+	"name": "吉林省",
+	"city": [{
+		"name": "长春市",
+		"area": ["市辖区", "南关区", "宽城区", "朝阳区", "二道区", "绿园区", "双阳区", "九台区", "农安县", "榆树市", "德惠市"]
+	}, {
+		"name": "吉林市",
+		"area": ["市辖区", "昌邑区", "龙潭区", "船营区", "丰满区", "永吉县", "蛟河市", "桦甸市", "舒兰市", "磐石市"]
+	}, {
+		"name": "四平市",
+		"area": ["市辖区", "铁西区", "铁东区", "梨树县", "伊通满族自治县", "公主岭市", "双辽市"]
+	}, {
+		"name": "辽源市",
+		"area": ["市辖区", "龙山区", "西安区", "东丰县", "东辽县"]
+	}, {
+		"name": "通化市",
+		"area": ["市辖区", "东昌区", "二道江区", "通化县", "辉南县", "柳河县", "梅河口市", "集安市"]
+	}, {
+		"name": "白山市",
+		"area": ["市辖区", "浑江区", "江源区", "抚松县", "靖宇县", "长白朝鲜族自治县", "临江市"]
+	}, {
+		"name": "松原市",
+		"area": ["市辖区", "宁江区", "前郭尔罗斯蒙古族自治县", "长岭县", "乾安县", "扶余市"]
+	}, {
+		"name": "白城市",
+		"area": ["市辖区", "洮北区", "镇赉县", "通榆县", "洮南市", "大安市"]
+	}, {
+		"name": "延边朝鲜族自治州",
+		"area": ["延吉市", "图们市", "敦化市", "珲春市", "龙井市", "和龙市", "汪清县", "安图县"]
+	}]
+}, {
+	"name": "黑龙江省",
+	"city": [{
+		"name": "哈尔滨市",
+		"area": ["市辖区", "道里区", "南岗区", "道外区", "平房区", "松北区", "香坊区", "呼兰区", "阿城区", "双城区", "依兰县", "方正县", "宾县",
+			"巴彦县", "木兰县", "通河县", "延寿县", "尚志市", "五常市"
+		]
+	}, {
+		"name": "齐齐哈尔市",
+		"area": ["市辖区", "龙沙区", "建华区", "铁锋区", "昂昂溪区", "富拉尔基区", "碾子山区", "梅里斯达斡尔族区", "龙江县", "依安县", "泰来县",
+			"甘南县", "富裕县", "克山县", "克东县", "拜泉县", "讷河市"
+		]
+	}, {
+		"name": "鸡西市",
+		"area": ["市辖区", "鸡冠区", "恒山区", "滴道区", "梨树区", "城子河区", "麻山区", "鸡东县", "虎林市", "密山市"]
+	}, {
+		"name": "鹤岗市",
+		"area": ["市辖区", "向阳区", "工农区", "南山区", "兴安区", "东山区", "兴山区", "萝北县", "绥滨县"]
+	}, {
+		"name": "双鸭山市",
+		"area": ["市辖区", "尖山区", "岭东区", "四方台区", "宝山区", "集贤县", "友谊县", "宝清县", "饶河县"]
+	}, {
+		"name": "大庆市",
+		"area": ["市辖区", "萨尔图区", "龙凤区", "让胡路区", "红岗区", "大同区", "肇州县", "肇源县", "林甸县", "杜尔伯特蒙古族自治县"]
+	}, {
+		"name": "伊春市",
+		"area": ["市辖区", "伊春区", "南岔区", "友好区", "西林区", "翠峦区", "新青区", "美溪区", "金山屯区", "五营区", "乌马河区", "汤旺河区",
+			"带岭区", "乌伊岭区", "红星区", "上甘岭区", "嘉荫县", "铁力市"
+		]
+	}, {
+		"name": "佳木斯市",
+		"area": ["市辖区", "向阳区", "前进区", "东风区", "郊区", "桦南县", "桦川县", "汤原县", "同江市", "富锦市", "抚远市"]
+	}, {
+		"name": "七台河市",
+		"area": ["市辖区", "新兴区", "桃山区", "茄子河区", "勃利县"]
+	}, {
+		"name": "牡丹江市",
+		"area": ["市辖区", "东安区", "阳明区", "爱民区", "西安区", "林口县", "绥芬河市", "海林市", "宁安市", "穆棱市", "东宁市"]
+	}, {
+		"name": "黑河市",
+		"area": ["市辖区", "爱辉区", "嫩江县", "逊克县", "孙吴县", "北安市", "五大连池市"]
+	}, {
+		"name": "绥化市",
+		"area": ["市辖区", "北林区", "望奎县", "兰西县", "青冈县", "庆安县", "明水县", "绥棱县", "安达市", "肇东市", "海伦市"]
+	}, {
+		"name": "大兴安岭地区",
+		"area": ["呼玛县", "塔河县", "漠河县"]
+	}]
+}, {
+	"name": "市辖区",
+	"city": [{
+		"name": "上海市",
+		"area": ["黄浦区", "徐汇区", "长宁区", "静安区", "普陀区", "虹口区", "杨浦区", "闵行区", "宝山区", "嘉定区", "浦东新区", "金山区", "松江区",
+			"青浦区", "奉贤区", "崇明区"
+		]
+	}]
+}, {
+	"name": "江苏省",
+	"city": [{
+		"name": "南京市",
+		"area": ["市辖区", "玄武区", "秦淮区", "建邺区", "鼓楼区", "浦口区", "栖霞区", "雨花台区", "江宁区", "六合区", "溧水区", "高淳区"]
+	}, {
+		"name": "无锡市",
+		"area": ["市辖区", "锡山区", "惠山区", "滨湖区", "梁溪区", "新吴区", "江阴市", "宜兴市"]
+	}, {
+		"name": "徐州市",
+		"area": ["市辖区", "鼓楼区", "云龙区", "贾汪区", "泉山区", "铜山区", "丰县", "沛县", "睢宁县", "新沂市", "邳州市"]
+	}, {
+		"name": "常州市",
+		"area": ["市辖区", "天宁区", "钟楼区", "新北区", "武进区", "金坛区", "溧阳市"]
+	}, {
+		"name": "苏州市",
+		"area": ["市辖区", "虎丘区", "吴中区", "相城区", "姑苏区", "吴江区", "常熟市", "张家港市", "昆山市", "太仓市"]
+	}, {
+		"name": "南通市",
+		"area": ["市辖区", "崇川区", "港闸区", "通州区", "海安县", "如东县", "启东市", "如皋市", "海门市"]
+	}, {
+		"name": "连云港市",
+		"area": ["市辖区", "连云区", "海州区", "赣榆区", "东海县", "灌云县", "灌南县"]
+	}, {
+		"name": "淮安市",
+		"area": ["市辖区", "淮安区", "淮阴区", "清江浦区", "洪泽区", "涟水县", "盱眙县", "金湖县"]
+	}, {
+		"name": "盐城市",
+		"area": ["市辖区", "亭湖区", "盐都区", "大丰区", "响水县", "滨海县", "阜宁县", "射阳县", "建湖县", "东台市"]
+	}, {
+		"name": "扬州市",
+		"area": ["市辖区", "广陵区", "邗江区", "江都区", "宝应县", "仪征市", "高邮市"]
+	}, {
+		"name": "镇江市",
+		"area": ["市辖区", "京口区", "润州区", "丹徒区", "丹阳市", "扬中市", "句容市"]
+	}, {
+		"name": "泰州市",
+		"area": ["市辖区", "海陵区", "高港区", "姜堰区", "兴化市", "靖江市", "泰兴市"]
+	}, {
+		"name": "宿迁市",
+		"area": ["市辖区", "宿城区", "宿豫区", "沭阳县", "泗阳县", "泗洪县"]
+	}]
+}, {
+	"name": "浙江省",
+	"city": [{
+		"name": "杭州市",
+		"area": ["市辖区", "上城区", "下城区", "江干区", "拱墅区", "西湖区", "滨江区", "萧山区", "余杭区", "富阳区", "桐庐县", "淳安县", "建德市",
+			"临安市"
+		]
+	}, {
+		"name": "宁波市",
+		"area": ["市辖区", "海曙区", "江东区", "江北区", "北仑区", "镇海区", "鄞州区", "象山县", "宁海县", "余姚市", "慈溪市", "奉化市"]
+	}, {
+		"name": "温州市",
+		"area": ["市辖区", "鹿城区", "龙湾区", "瓯海区", "洞头区", "永嘉县", "平阳县", "苍南县", "文成县", "泰顺县", "瑞安市", "乐清市"]
+	}, {
+		"name": "嘉兴市",
+		"area": ["市辖区", "南湖区", "秀洲区", "嘉善县", "海盐县", "海宁市", "平湖市", "桐乡市"]
+	}, {
+		"name": "湖州市",
+		"area": ["市辖区", "吴兴区", "南浔区", "德清县", "长兴县", "安吉县"]
+	}, {
+		"name": "绍兴市",
+		"area": ["市辖区", "越城区", "柯桥区", "上虞区", "新昌县", "诸暨市", "嵊州市"]
+	}, {
+		"name": "金华市",
+		"area": ["市辖区", "婺城区", "金东区", "武义县", "浦江县", "磐安县", "兰溪市", "义乌市", "东阳市", "永康市"]
+	}, {
+		"name": "衢州市",
+		"area": ["市辖区", "柯城区", "衢江区", "常山县", "开化县", "龙游县", "江山市"]
+	}, {
+		"name": "舟山市",
+		"area": ["市辖区", "定海区", "普陀区", "岱山县", "嵊泗县"]
+	}, {
+		"name": "台州市",
+		"area": ["市辖区", "椒江区", "黄岩区", "路桥区", "玉环县", "三门县", "天台县", "仙居县", "温岭市", "临海市"]
+	}, {
+		"name": "丽水市",
+		"area": ["市辖区", "莲都区", "青田县", "缙云县", "遂昌县", "松阳县", "云和县", "庆元县", "景宁畲族自治县", "龙泉市"]
+	}]
+}, {
+	"name": "安徽省",
+	"city": [{
+		"name": "合肥市",
+		"area": ["市辖区", "瑶海区", "庐阳区", "蜀山区", "包河区", "长丰县", "肥东县", "肥西县", "庐江县", "巢湖市"]
+	}, {
+		"name": "芜湖市",
+		"area": ["市辖区", "镜湖区", "弋江区", "鸠江区", "三山区", "芜湖县", "繁昌县", "南陵县", "无为县"]
+	}, {
+		"name": "蚌埠市",
+		"area": ["市辖区", "龙子湖区", "蚌山区", "禹会区", "淮上区", "怀远县", "五河县", "固镇县"]
+	}, {
+		"name": "淮南市",
+		"area": ["市辖区", "大通区", "田家庵区", "谢家集区", "八公山区", "潘集区", "凤台县", "寿县"]
+	}, {
+		"name": "马鞍山市",
+		"area": ["市辖区", "花山区", "雨山区", "博望区", "当涂县", "含山县", "和县"]
+	}, {
+		"name": "淮北市",
+		"area": ["市辖区", "杜集区", "相山区", "烈山区", "濉溪县"]
+	}, {
+		"name": "铜陵市",
+		"area": ["市辖区", "铜官区", "义安区", "郊区", "枞阳县"]
+	}, {
+		"name": "安庆市",
+		"area": ["市辖区", "迎江区", "大观区", "宜秀区", "怀宁县", "潜山县", "太湖县", "宿松县", "望江县", "岳西县", "桐城市"]
+	}, {
+		"name": "黄山市",
+		"area": ["市辖区", "屯溪区", "黄山区", "徽州区", "歙县", "休宁县", "黟县", "祁门县"]
+	}, {
+		"name": "滁州市",
+		"area": ["市辖区", "琅琊区", "南谯区", "来安县", "全椒县", "定远县", "凤阳县", "天长市", "明光市"]
+	}, {
+		"name": "阜阳市",
+		"area": ["市辖区", "颍州区", "颍东区", "颍泉区", "临泉县", "太和县", "阜南县", "颍上县", "界首市"]
+	}, {
+		"name": "宿州市",
+		"area": ["市辖区", "埇桥区", "砀山县", "萧县", "灵璧县", "泗县"]
+	}, {
+		"name": "六安市",
+		"area": ["市辖区", "金安区", "裕安区", "叶集区", "霍邱县", "舒城县", "金寨县", "霍山县"]
+	}, {
+		"name": "亳州市",
+		"area": ["市辖区", "谯城区", "涡阳县", "蒙城县", "利辛县"]
+	}, {
+		"name": "池州市",
+		"area": ["市辖区", "贵池区", "东至县", "石台县", "青阳县"]
+	}, {
+		"name": "宣城市",
+		"area": ["市辖区", "宣州区", "郎溪县", "广德县", "泾县", "绩溪县", "旌德县", "宁国市"]
+	}]
+}, {
+	"name": "福建省",
+	"city": [{
+		"name": "福州市",
+		"area": ["市辖区", "鼓楼区", "台江区", "仓山区", "马尾区", "晋安区", "闽侯县", "连江县", "罗源县", "闽清县", "永泰县", "平潭县", "福清市",
+			"长乐市"
+		]
+	}, {
+		"name": "厦门市",
+		"area": ["市辖区", "思明区", "海沧区", "湖里区", "集美区", "同安区", "翔安区"]
+	}, {
+		"name": "莆田市",
+		"area": ["市辖区", "城厢区", "涵江区", "荔城区", "秀屿区", "仙游县"]
+	}, {
+		"name": "三明市",
+		"area": ["市辖区", "梅列区", "三元区", "明溪县", "清流县", "宁化县", "大田县", "尤溪县", "沙县", "将乐县", "泰宁县", "建宁县", "永安市"]
+	}, {
+		"name": "泉州市",
+		"area": ["市辖区", "鲤城区", "丰泽区", "洛江区", "泉港区", "惠安县", "安溪县", "永春县", "德化县", "金门县", "石狮市", "晋江市", "南安市"]
+	}, {
+		"name": "漳州市",
+		"area": ["市辖区", "芗城区", "龙文区", "云霄县", "漳浦县", "诏安县", "长泰县", "东山县", "南靖县", "平和县", "华安县", "龙海市"]
+	}, {
+		"name": "南平市",
+		"area": ["市辖区", "延平区", "建阳区", "顺昌县", "浦城县", "光泽县", "松溪县", "政和县", "邵武市", "武夷山市", "建瓯市"]
+	}, {
+		"name": "龙岩市",
+		"area": ["市辖区", "新罗区", "永定区", "长汀县", "上杭县", "武平县", "连城县", "漳平市"]
+	}, {
+		"name": "宁德市",
+		"area": ["市辖区", "蕉城区", "霞浦县", "古田县", "屏南县", "寿宁县", "周宁县", "柘荣县", "福安市", "福鼎市"]
+	}]
+}, {
+	"name": "江西省",
+	"city": [{
+		"name": "南昌市",
+		"area": ["市辖区", "东湖区", "西湖区", "青云谱区", "湾里区", "青山湖区", "新建区", "南昌县", "安义县", "进贤县"]
+	}, {
+		"name": "景德镇市",
+		"area": ["市辖区", "昌江区", "珠山区", "浮梁县", "乐平市"]
+	}, {
+		"name": "萍乡市",
+		"area": ["市辖区", "安源区", "湘东区", "莲花县", "上栗县", "芦溪县"]
+	}, {
+		"name": "九江市",
+		"area": ["市辖区", "濂溪区", "浔阳区", "九江县", "武宁县", "修水县", "永修县", "德安县", "都昌县", "湖口县", "彭泽县", "瑞昌市", "共青城市",
+			"庐山市"
+		]
+	}, {
+		"name": "新余市",
+		"area": ["市辖区", "渝水区", "分宜县"]
+	}, {
+		"name": "鹰潭市",
+		"area": ["市辖区", "月湖区", "余江县", "贵溪市"]
+	}, {
+		"name": "赣州市",
+		"area": ["市辖区", "章贡区", "南康区", "赣县", "信丰县", "大余县", "上犹县", "崇义县", "安远县", "龙南县", "定南县", "全南县", "宁都县",
+			"于都县", "兴国县", "会昌县", "寻乌县", "石城县", "瑞金市"
+		]
+	}, {
+		"name": "吉安市",
+		"area": ["市辖区", "吉州区", "青原区", "吉安县", "吉水县", "峡江县", "新干县", "永丰县", "泰和县", "遂川县", "万安县", "安福县", "永新县",
+			"井冈山市"
+		]
+	}, {
+		"name": "宜春市",
+		"area": ["市辖区", "袁州区", "奉新县", "万载县", "上高县", "宜丰县", "靖安县", "铜鼓县", "丰城市", "樟树市", "高安市"]
+	}, {
+		"name": "抚州市",
+		"area": ["市辖区", "临川区", "南城县", "黎川县", "南丰县", "崇仁县", "乐安县", "宜黄县", "金溪县", "资溪县", "东乡县", "广昌县"]
+	}, {
+		"name": "上饶市",
+		"area": ["市辖区", "信州区", "广丰区", "上饶县", "玉山县", "铅山县", "横峰县", "弋阳县", "余干县", "鄱阳县", "万年县", "婺源县", "德兴市"]
+	}]
+}, {
+	"name": "山东省",
+	"city": [{
+		"name": "济南市",
+		"area": ["市辖区", "历下区", "市中区", "槐荫区", "天桥区", "历城区", "长清区", "平阴县", "济阳县", "商河县", "章丘市"]
+	}, {
+		"name": "青岛市",
+		"area": ["市辖区", "市南区", "市北区", "黄岛区", "崂山区", "李沧区", "城阳区", "胶州市", "即墨市", "平度市", "莱西市"]
+	}, {
+		"name": "淄博市",
+		"area": ["市辖区", "淄川区", "张店区", "博山区", "临淄区", "周村区", "桓台县", "高青县", "沂源县"]
+	}, {
+		"name": "枣庄市",
+		"area": ["市辖区", "市中区", "薛城区", "峄城区", "台儿庄区", "山亭区", "滕州市"]
+	}, {
+		"name": "东营市",
+		"area": ["市辖区", "东营区", "河口区", "垦利区", "利津县", "广饶县"]
+	}, {
+		"name": "烟台市",
+		"area": ["市辖区", "芝罘区", "福山区", "牟平区", "莱山区", "长岛县", "龙口市", "莱阳市", "莱州市", "蓬莱市", "招远市", "栖霞市", "海阳市"]
+	}, {
+		"name": "潍坊市",
+		"area": ["市辖区", "潍城区", "寒亭区", "坊子区", "奎文区", "临朐县", "昌乐县", "青州市", "诸城市", "寿光市", "安丘市", "高密市", "昌邑市"]
+	}, {
+		"name": "济宁市",
+		"area": ["市辖区", "任城区", "兖州区", "微山县", "鱼台县", "金乡县", "嘉祥县", "汶上县", "泗水县", "梁山县", "曲阜市", "邹城市"]
+	}, {
+		"name": "泰安市",
+		"area": ["市辖区", "泰山区", "岱岳区", "宁阳县", "东平县", "新泰市", "肥城市"]
+	}, {
+		"name": "威海市",
+		"area": ["市辖区", "环翠区", "文登区", "荣成市", "乳山市"]
+	}, {
+		"name": "日照市",
+		"area": ["市辖区", "东港区", "岚山区", "五莲县", "莒县"]
+	}, {
+		"name": "莱芜市",
+		"area": ["市辖区", "莱城区", "钢城区"]
+	}, {
+		"name": "临沂市",
+		"area": ["市辖区", "兰山区", "罗庄区", "河东区", "沂南县", "郯城县", "沂水县", "兰陵县", "费县", "平邑县", "莒南县", "蒙阴县", "临沭县"]
+	}, {
+		"name": "德州市",
+		"area": ["市辖区", "德城区", "陵城区", "宁津县", "庆云县", "临邑县", "齐河县", "平原县", "夏津县", "武城县", "乐陵市", "禹城市"]
+	}, {
+		"name": "聊城市",
+		"area": ["市辖区", "东昌府区", "阳谷县", "莘县", "茌平县", "东阿县", "冠县", "高唐县", "临清市"]
+	}, {
+		"name": "滨州市",
+		"area": ["市辖区", "滨城区", "沾化区", "惠民县", "阳信县", "无棣县", "博兴县", "邹平县"]
+	}, {
+		"name": "菏泽市",
+		"area": ["市辖区", "牡丹区", "定陶区", "曹县", "单县", "成武县", "巨野县", "郓城县", "鄄城县", "东明县"]
+	}]
+}, {
+	"name": "河南省",
+	"city": [{
+		"name": "郑州市",
+		"area": ["市辖区", "中原区", "二七区", "管城回族区", "金水区", "上街区", "惠济区", "中牟县", "巩义市", "荥阳市", "新密市", "新郑市",
+			"登封市"
+		]
+	}, {
+		"name": "开封市",
+		"area": ["市辖区", "龙亭区", "顺河回族区", "鼓楼区", "禹王台区", "金明区", "祥符区", "杞县", "通许县", "尉氏县", "兰考县"]
+	}, {
+		"name": "洛阳市",
+		"area": ["市辖区", "老城区", "西工区", "瀍河回族区", "涧西区", "吉利区", "洛龙区", "孟津县", "新安县", "栾川县", "嵩县", "汝阳县", "宜阳县",
+			"洛宁县", "伊川县", "偃师市"
+		]
+	}, {
+		"name": "平顶山市",
+		"area": ["市辖区", "新华区", "卫东区", "石龙区", "湛河区", "宝丰县", "叶县", "鲁山县", "郏县", "舞钢市", "汝州市"]
+	}, {
+		"name": "安阳市",
+		"area": ["市辖区", "文峰区", "北关区", "殷都区", "龙安区", "安阳县", "汤阴县", "滑县", "内黄县", "林州市"]
+	}, {
+		"name": "鹤壁市",
+		"area": ["市辖区", "鹤山区", "山城区", "淇滨区", "浚县", "淇县"]
+	}, {
+		"name": "新乡市",
+		"area": ["市辖区", "红旗区", "卫滨区", "凤泉区", "牧野区", "新乡县", "获嘉县", "原阳县", "延津县", "封丘县", "长垣县", "卫辉市", "辉县市"]
+	}, {
+		"name": "焦作市",
+		"area": ["市辖区", "解放区", "中站区", "马村区", "山阳区", "修武县", "博爱县", "武陟县", "温县", "沁阳市", "孟州市"]
+	}, {
+		"name": "濮阳市",
+		"area": ["市辖区", "华龙区", "清丰县", "南乐县", "范县", "台前县", "濮阳县"]
+	}, {
+		"name": "许昌市",
+		"area": ["市辖区", "魏都区", "许昌县", "鄢陵县", "襄城县", "禹州市", "长葛市"]
+	}, {
+		"name": "漯河市",
+		"area": ["市辖区", "源汇区", "郾城区", "召陵区", "舞阳县", "临颍县"]
+	}, {
+		"name": "三门峡市",
+		"area": ["市辖区", "湖滨区", "陕州区", "渑池县", "卢氏县", "义马市", "灵宝市"]
+	}, {
+		"name": "南阳市",
+		"area": ["市辖区", "宛城区", "卧龙区", "南召县", "方城县", "西峡县", "镇平县", "内乡县", "淅川县", "社旗县", "唐河县", "新野县", "桐柏县",
+			"邓州市"
+		]
+	}, {
+		"name": "商丘市",
+		"area": ["市辖区", "梁园区", "睢阳区", "民权县", "睢县", "宁陵县", "柘城县", "虞城县", "夏邑县", "永城市"]
+	}, {
+		"name": "信阳市",
+		"area": ["市辖区", "浉河区", "平桥区", "罗山县", "光山县", "新县", "商城县", "固始县", "潢川县", "淮滨县", "息县"]
+	}, {
+		"name": "周口市",
+		"area": ["市辖区", "川汇区", "扶沟县", "西华县", "商水县", "沈丘县", "郸城县", "淮阳县", "太康县", "鹿邑县", "项城市"]
+	}, {
+		"name": "驻马店市",
+		"area": ["市辖区", "驿城区", "西平县", "上蔡县", "平舆县", "正阳县", "确山县", "泌阳县", "汝南县", "遂平县", "新蔡县"]
+	}, {
+		"name": "直辖县",
+		"area": ["济源市"]
+	}]
+}, {
+	"name": "湖北省",
+	"city": [{
+		"name": "武汉市",
+		"area": ["市辖区", "江岸区", "江汉区", "硚口区", "汉阳区", "武昌区", "青山区", "洪山区", "东西湖区", "汉南区", "蔡甸区", "江夏区", "黄陂区",
+			"新洲区"
+		]
+	}, {
+		"name": "黄石市",
+		"area": ["市辖区", "黄石港区", "西塞山区", "下陆区", "铁山区", "阳新县", "大冶市"]
+	}, {
+		"name": "十堰市",
+		"area": ["市辖区", "茅箭区", "张湾区", "郧阳区", "郧西县", "竹山县", "竹溪县", "房县", "丹江口市"]
+	}, {
+		"name": "宜昌市",
+		"area": ["市辖区", "西陵区", "伍家岗区", "点军区", "猇亭区", "夷陵区", "远安县", "兴山县", "秭归县", "长阳土家族自治县", "五峰土家族自治县",
+			"宜都市", "当阳市", "枝江市"
+		]
+	}, {
+		"name": "襄阳市",
+		"area": ["市辖区", "襄城区", "樊城区", "襄州区", "南漳县", "谷城县", "保康县", "老河口市", "枣阳市", "宜城市"]
+	}, {
+		"name": "鄂州市",
+		"area": ["市辖区", "梁子湖区", "华容区", "鄂城区"]
+	}, {
+		"name": "荆门市",
+		"area": ["市辖区", "东宝区", "掇刀区", "京山县", "沙洋县", "钟祥市"]
+	}, {
+		"name": "孝感市",
+		"area": ["市辖区", "孝南区", "孝昌县", "大悟县", "云梦县", "应城市", "安陆市", "汉川市"]
+	}, {
+		"name": "荆州市",
+		"area": ["市辖区", "沙市区", "荆州区", "公安县", "监利县", "江陵县", "石首市", "洪湖市", "松滋市"]
+	}, {
+		"name": "黄冈市",
+		"area": ["市辖区", "黄州区", "团风县", "红安县", "罗田县", "英山县", "浠水县", "蕲春县", "黄梅县", "麻城市", "武穴市"]
+	}, {
+		"name": "咸宁市",
+		"area": ["市辖区", "咸安区", "嘉鱼县", "通城县", "崇阳县", "通山县", "赤壁市"]
+	}, {
+		"name": "随州市",
+		"area": ["市辖区", "曾都区", "随县", "广水市"]
+	}, {
+		"name": "恩施土家族苗族自治州",
+		"area": ["恩施市", "利川市", "建始县", "巴东县", "宣恩县", "咸丰县", "来凤县", "鹤峰县"]
+	}, {
+		"name": "直辖县",
+		"area": ["仙桃市", "潜江市", "天门市", "神农架林区"]
+	}]
+}, {
+	"name": "湖南省",
+	"city": [{
+		"name": "长沙市",
+		"area": ["市辖区", "芙蓉区", "天心区", "岳麓区", "开福区", "雨花区", "望城区", "长沙县", "宁乡县", "浏阳市"]
+	}, {
+		"name": "株洲市",
+		"area": ["市辖区", "荷塘区", "芦淞区", "石峰区", "天元区", "株洲县", "攸县", "茶陵县", "炎陵县", "醴陵市"]
+	}, {
+		"name": "湘潭市",
+		"area": ["市辖区", "雨湖区", "岳塘区", "湘潭县", "湘乡市", "韶山市"]
+	}, {
+		"name": "衡阳市",
+		"area": ["市辖区", "珠晖区", "雁峰区", "石鼓区", "蒸湘区", "南岳区", "衡阳县", "衡南县", "衡山县", "衡东县", "祁东县", "耒阳市", "常宁市"]
+	}, {
+		"name": "邵阳市",
+		"area": ["市辖区", "双清区", "大祥区", "北塔区", "邵东县", "新邵县", "邵阳县", "隆回县", "洞口县", "绥宁县", "新宁县", "城步苗族自治县",
+			"武冈市"
+		]
+	}, {
+		"name": "岳阳市",
+		"area": ["市辖区", "岳阳楼区", "云溪区", "君山区", "岳阳县", "华容县", "湘阴县", "平江县", "汨罗市", "临湘市"]
+	}, {
+		"name": "常德市",
+		"area": ["市辖区", "武陵区", "鼎城区", "安乡县", "汉寿县", "澧县", "临澧县", "桃源县", "石门县", "津市市"]
+	}, {
+		"name": "张家界市",
+		"area": ["市辖区", "永定区", "武陵源区", "慈利县", "桑植县"]
+	}, {
+		"name": "益阳市",
+		"area": ["市辖区", "资阳区", "赫山区", "南县", "桃江县", "安化县", "沅江市"]
+	}, {
+		"name": "郴州市",
+		"area": ["市辖区", "北湖区", "苏仙区", "桂阳县", "宜章县", "永兴县", "嘉禾县", "临武县", "汝城县", "桂东县", "安仁县", "资兴市"]
+	}, {
+		"name": "永州市",
+		"area": ["市辖区", "零陵区", "冷水滩区", "祁阳县", "东安县", "双牌县", "道县", "江永县", "宁远县", "蓝山县", "新田县", "江华瑶族自治县"]
+	}, {
+		"name": "怀化市",
+		"area": ["市辖区", "鹤城区", "中方县", "沅陵县", "辰溪县", "溆浦县", "会同县", "麻阳苗族自治县", "新晃侗族自治县", "芷江侗族自治县",
+			"靖州苗族侗族自治县", "通道侗族自治县", "洪江市"
+		]
+	}, {
+		"name": "娄底市",
+		"area": ["市辖区", "娄星区", "双峰县", "新化县", "冷水江市", "涟源市"]
+	}, {
+		"name": "湘西土家族苗族自治州",
+		"area": ["吉首市", "泸溪县", "凤凰县", "花垣县", "保靖县", "古丈县", "永顺县", "龙山县"]
+	}]
+}, {
+	"name": "广东省",
+	"city": [{
+		"name": "广州市",
+		"area": ["市辖区", "荔湾区", "越秀区", "海珠区", "天河区", "白云区", "黄埔区", "番禺区", "花都区", "南沙区", "从化区", "增城区"]
+	}, {
+		"name": "韶关市",
+		"area": ["市辖区", "武江区", "浈江区", "曲江区", "始兴县", "仁化县", "翁源县", "乳源瑶族自治县", "新丰县", "乐昌市", "南雄市"]
+	}, {
+		"name": "深圳市",
+		"area": ["市辖区", "罗湖区", "福田区", "南山区", "宝安区", "龙岗区", "盐田区"]
+	}, {
+		"name": "珠海市",
+		"area": ["市辖区", "香洲区", "斗门区", "金湾区"]
+	}, {
+		"name": "汕头市",
+		"area": ["市辖区", "龙湖区", "金平区", "濠江区", "潮阳区", "潮南区", "澄海区", "南澳县"]
+	}, {
+		"name": "佛山市",
+		"area": ["市辖区", "禅城区", "南海区", "顺德区", "三水区", "高明区"]
+	}, {
+		"name": "江门市",
+		"area": ["市辖区", "蓬江区", "江海区", "新会区", "台山市", "开平市", "鹤山市", "恩平市"]
+	}, {
+		"name": "湛江市",
+		"area": ["市辖区", "赤坎区", "霞山区", "坡头区", "麻章区", "遂溪县", "徐闻县", "廉江市", "雷州市", "吴川市"]
+	}, {
+		"name": "茂名市",
+		"area": ["市辖区", "茂南区", "电白区", "高州市", "化州市", "信宜市"]
+	}, {
+		"name": "肇庆市",
+		"area": ["市辖区", "端州区", "鼎湖区", "高要区", "广宁县", "怀集县", "封开县", "德庆县", "四会市"]
+	}, {
+		"name": "惠州市",
+		"area": ["市辖区", "惠城区", "惠阳区", "博罗县", "惠东县", "龙门县"]
+	}, {
+		"name": "梅州市",
+		"area": ["市辖区", "梅江区", "梅县区", "大埔县", "丰顺县", "五华县", "平远县", "蕉岭县", "兴宁市"]
+	}, {
+		"name": "汕尾市",
+		"area": ["市辖区", "城区", "海丰县", "陆河县", "陆丰市"]
+	}, {
+		"name": "河源市",
+		"area": ["市辖区", "源城区", "紫金县", "龙川县", "连平县", "和平县", "东源县"]
+	}, {
+		"name": "阳江市",
+		"area": ["市辖区", "江城区", "阳东区", "阳西县", "阳春市"]
+	}, {
+		"name": "清远市",
+		"area": ["市辖区", "清城区", "清新区", "佛冈县", "阳山县", "连山壮族瑶族自治县", "连南瑶族自治县", "英德市", "连州市"]
+	}, {
+		"name": "东莞市",
+		"area": ["东城街道办事处", "南城街道办事处", "万江街道办事处", "莞城街道办事处", "石碣镇", "石龙镇", "茶山镇", "石排镇", "企石镇", "横沥镇",
+			"桥头镇", "谢岗镇", "东坑镇", "常平镇", "寮步镇", "樟木头镇", "大朗镇", "黄江镇", "清溪镇", "塘厦镇", "凤岗镇", "大岭山镇", "长安镇",
+			"虎门镇", "厚街镇", "沙田镇", "道滘镇", "洪梅镇", "麻涌镇", "望牛墩镇", "中堂镇", "高埗镇", "松山湖管委会", "虎门港管委会", "东莞生态园"
+		]
+	}, {
+		"name": "中山市",
+		"area": ["石岐区街道办事处", "东区街道办事处", "火炬开发区街道办事处", "西区街道办事处", "南区街道办事处", "五桂山街道办事处", "小榄镇", "黄圃镇", "民众镇",
+			"东凤镇", "东升镇", "古镇镇", "沙溪镇", "坦洲镇", "港口镇", "三角镇", "横栏镇", "南头镇", "阜沙镇", "南朗镇", "三乡镇", "板芙镇",
+			"大涌镇", "神湾镇"
+		]
+	}, {
+		"name": "潮州市",
+		"area": ["市辖区", "湘桥区", "潮安区", "饶平县"]
+	}, {
+		"name": "揭阳市",
+		"area": ["市辖区", "榕城区", "揭东区", "揭西县", "惠来县", "普宁市"]
+	}, {
+		"name": "云浮市",
+		"area": ["市辖区", "云城区", "云安区", "新兴县", "郁南县", "罗定市"]
+	}]
+}, {
+	"name": "广西壮族自治区",
+	"city": [{
+		"name": "南宁市",
+		"area": ["市辖区", "兴宁区", "青秀区", "江南区", "西乡塘区", "良庆区", "邕宁区", "武鸣区", "隆安县", "马山县", "上林县", "宾阳县", "横县"]
+	}, {
+		"name": "柳州市",
+		"area": ["市辖区", "城中区", "鱼峰区", "柳南区", "柳北区", "柳江区", "柳城县", "鹿寨县", "融安县", "融水苗族自治县", "三江侗族自治县"]
+	}, {
+		"name": "桂林市",
+		"area": ["市辖区", "秀峰区", "叠彩区", "象山区", "七星区", "雁山区", "临桂区", "阳朔县", "灵川县", "全州县", "兴安县", "永福县", "灌阳县",
+			"龙胜各族自治县", "资源县", "平乐县", "荔浦县", "恭城瑶族自治县"
+		]
+	}, {
+		"name": "梧州市",
+		"area": ["市辖区", "万秀区", "长洲区", "龙圩区", "苍梧县", "藤县", "蒙山县", "岑溪市"]
+	}, {
+		"name": "北海市",
+		"area": ["市辖区", "海城区", "银海区", "铁山港区", "合浦县"]
+	}, {
+		"name": "防城港市",
+		"area": ["市辖区", "港口区", "防城区", "上思县", "东兴市"]
+	}, {
+		"name": "钦州市",
+		"area": ["市辖区", "钦南区", "钦北区", "灵山县", "浦北县"]
+	}, {
+		"name": "贵港市",
+		"area": ["市辖区", "港北区", "港南区", "覃塘区", "平南县", "桂平市"]
+	}, {
+		"name": "玉林市",
+		"area": ["市辖区", "玉州区", "福绵区", "容县", "陆川县", "博白县", "兴业县", "北流市"]
+	}, {
+		"name": "百色市",
+		"area": ["市辖区", "右江区", "田阳县", "田东县", "平果县", "德保县", "那坡县", "凌云县", "乐业县", "田林县", "西林县", "隆林各族自治县",
+			"靖西市"
+		]
+	}, {
+		"name": "贺州市",
+		"area": ["市辖区", "八步区", "平桂区", "昭平县", "钟山县", "富川瑶族自治县"]
+	}, {
+		"name": "河池市",
+		"area": ["市辖区", "金城江区", "南丹县", "天峨县", "凤山县", "东兰县", "罗城仫佬族自治县", "环江毛南族自治县", "巴马瑶族自治县", "都安瑶族自治县",
+			"大化瑶族自治县", "宜州市"
+		]
+	}, {
+		"name": "来宾市",
+		"area": ["市辖区", "兴宾区", "忻城县", "象州县", "武宣县", "金秀瑶族自治县", "合山市"]
+	}, {
+		"name": "崇左市",
+		"area": ["市辖区", "江州区", "扶绥县", "宁明县", "龙州县", "大新县", "天等县", "凭祥市"]
+	}]
+}, {
+	"name": "海南省",
+	"city": [{
+		"name": "海口市",
+		"area": ["市辖区", "秀英区", "龙华区", "琼山区", "美兰区"]
+	}, {
+		"name": "三亚市",
+		"area": ["市辖区", "海棠区", "吉阳区", "天涯区", "崖州区"]
+	}, {
+		"name": "三沙市",
+		"area": ["西沙群岛", "南沙群岛", "中沙群岛的岛礁及其海域"]
+	}, {
+		"name": "儋州市",
+		"area": ["那大镇", "和庆镇", "南丰镇", "大成镇", "雅星镇", "兰洋镇", "光村镇", "木棠镇", "海头镇", "峨蔓镇", "三都镇", "王五镇", "白马井镇",
+			"中和镇", "排浦镇", "东成镇", "新州镇", "国营西培农场", "国营西联农场", "国营蓝洋农场", "国营八一农场", "洋浦经济开发区", "华南热作学院"
+		]
+	}, {
+		"name": "省直辖县级行政区域",
+		"area": ["五指山市", "琼海市", "文昌市", "万宁市", "东方市", "定安县", "屯昌县", "澄迈县", "临高县", "白沙黎族自治县", "昌江黎族自治县",
+			"乐东黎族自治县", "陵水黎族自治县", "保亭黎族苗族自治县", "琼中黎族苗族自治县"
+		]
+	}]
+}, {
+	"name": "重庆市",
+	"city": [{
+		"name": "市辖区",
+		"area": ["万州区", "涪陵区", "渝中区", "大渡口区", "江北区", "沙坪坝区", "九龙坡区", "南岸区", "北碚区", "綦江区", "大足区", "渝北区",
+			"巴南区", "黔江区", "长寿区", "江津区", "合川区", "永川区", "南川区", "璧山区", "铜梁区", "潼南区", "荣昌区", "开州区"
+		]
+	}, {
+		"name": "县",
+		"area": ["梁平县", "城口县", "丰都县", "垫江县", "武隆县", "忠县", "云阳县", "奉节县", "巫山县", "巫溪县", "石柱土家族自治县",
+			"秀山土家族苗族自治县", "酉阳土家族苗族自治县", "彭水苗族土家族自治县"
+		]
+	}]
+}, {
+	"name": "四川省",
+	"city": [{
+		"name": "成都市",
+		"area": ["市辖区", "锦江区", "青羊区", "金牛区", "武侯区", "成华区", "龙泉驿区", "青白江区", "新都区", "温江区", "双流区", "金堂县", "郫县",
+			"大邑县", "蒲江县", "新津县", "都江堰市", "彭州市", "邛崃市", "崇州市", "简阳市"
+		]
+	}, {
+		"name": "自贡市",
+		"area": ["市辖区", "自流井区", "贡井区", "大安区", "沿滩区", "荣县", "富顺县"]
+	}, {
+		"name": "攀枝花市",
+		"area": ["市辖区", "东区", "西区", "仁和区", "米易县", "盐边县"]
+	}, {
+		"name": "泸州市",
+		"area": ["市辖区", "江阳区", "纳溪区", "龙马潭区", "泸县", "合江县", "叙永县", "古蔺县"]
+	}, {
+		"name": "德阳市",
+		"area": ["市辖区", "旌阳区", "中江县", "罗江县", "广汉市", "什邡市", "绵竹市"]
+	}, {
+		"name": "绵阳市",
+		"area": ["市辖区", "涪城区", "游仙区", "安州区", "三台县", "盐亭县", "梓潼县", "北川羌族自治县", "平武县", "江油市"]
+	}, {
+		"name": "广元市",
+		"area": ["市辖区", "利州区", "昭化区", "朝天区", "旺苍县", "青川县", "剑阁县", "苍溪县"]
+	}, {
+		"name": "遂宁市",
+		"area": ["市辖区", "船山区", "安居区", "蓬溪县", "射洪县", "大英县"]
+	}, {
+		"name": "内江市",
+		"area": ["市辖区", "市中区", "东兴区", "威远县", "资中县", "隆昌县"]
+	}, {
+		"name": "乐山市",
+		"area": ["市辖区", "市中区", "沙湾区", "五通桥区", "金口河区", "犍为县", "井研县", "夹江县", "沐川县", "峨边彝族自治县", "马边彝族自治县",
+			"峨眉山市"
+		]
+	}, {
+		"name": "南充市",
+		"area": ["市辖区", "顺庆区", "高坪区", "嘉陵区", "南部县", "营山县", "蓬安县", "仪陇县", "西充县", "阆中市"]
+	}, {
+		"name": "眉山市",
+		"area": ["市辖区", "东坡区", "彭山区", "仁寿县", "洪雅县", "丹棱县", "青神县"]
+	}, {
+		"name": "宜宾市",
+		"area": ["市辖区", "翠屏区", "南溪区", "宜宾县", "江安县", "长宁县", "高县", "珙县", "筠连县", "兴文县", "屏山县"]
+	}, {
+		"name": "广安市",
+		"area": ["市辖区", "广安区", "前锋区", "岳池县", "武胜县", "邻水县", "华蓥市"]
+	}, {
+		"name": "达州市",
+		"area": ["市辖区", "通川区", "达川区", "宣汉县", "开江县", "大竹县", "渠县", "万源市"]
+	}, {
+		"name": "雅安市",
+		"area": ["市辖区", "雨城区", "名山区", "荥经县", "汉源县", "石棉县", "天全县", "芦山县", "宝兴县"]
+	}, {
+		"name": "巴中市",
+		"area": ["市辖区", "巴州区", "恩阳区", "通江县", "南江县", "平昌县"]
+	}, {
+		"name": "资阳市",
+		"area": ["市辖区", "雁江区", "安岳县", "乐至县"]
+	}, {
+		"name": "阿坝藏族羌族自治州",
+		"area": ["马尔康市", "汶川县", "理县", "茂县", "松潘县", "九寨沟县", "金川县", "小金县", "黑水县", "壤塘县", "阿坝县", "若尔盖县", "红原县"]
+	}, {
+		"name": "甘孜藏族自治州",
+		"area": ["康定市", "泸定县", "丹巴县", "九龙县", "雅江县", "道孚县", "炉霍县", "甘孜县", "新龙县", "德格县", "白玉县", "石渠县", "色达县",
+			"理塘县", "巴塘县", "乡城县", "稻城县", "得荣县"
+		]
+	}, {
+		"name": "凉山彝族自治州",
+		"area": ["西昌市", "木里藏族自治县", "盐源县", "德昌县", "会理县", "会东县", "宁南县", "普格县", "布拖县", "金阳县", "昭觉县", "喜德县",
+			"冕宁县", "越西县", "甘洛县", "美姑县", "雷波县"
+		]
+	}]
+}, {
+	"name": "贵州省",
+	"city": [{
+		"name": "贵阳市",
+		"area": ["市辖区", "南明区", "云岩区", "花溪区", "乌当区", "白云区", "观山湖区", "开阳县", "息烽县", "修文县", "清镇市"]
+	}, {
+		"name": "六盘水市",
+		"area": ["钟山区", "六枝特区", "水城县", "盘县"]
+	}, {
+		"name": "遵义市",
+		"area": ["市辖区", "红花岗区", "汇川区", "播州区", "桐梓县", "绥阳县", "正安县", "道真仡佬族苗族自治县", "务川仡佬族苗族自治县", "凤冈县", "湄潭县",
+			"余庆县", "习水县", "赤水市", "仁怀市"
+		]
+	}, {
+		"name": "安顺市",
+		"area": ["市辖区", "西秀区", "平坝区", "普定县", "镇宁布依族苗族自治县", "关岭布依族苗族自治县", "紫云苗族布依族自治县"]
+	}, {
+		"name": "毕节市",
+		"area": ["市辖区", "七星关区", "大方县", "黔西县", "金沙县", "织金县", "纳雍县", "威宁彝族回族苗族自治县", "赫章县"]
+	}, {
+		"name": "铜仁市",
+		"area": ["市辖区", "碧江区", "万山区", "江口县", "玉屏侗族自治县", "石阡县", "思南县", "印江土家族苗族自治县", "德江县", "沿河土家族自治县",
+			"松桃苗族自治县"
+		]
+	}, {
+		"name": "黔西南布依族苗族自治州",
+		"area": ["兴义市", "兴仁县", "普安县", "晴隆县", "贞丰县", "望谟县", "册亨县", "安龙县"]
+	}, {
+		"name": "黔东南苗族侗族自治州",
+		"area": ["凯里市", "黄平县", "施秉县", "三穗县", "镇远县", "岑巩县", "天柱县", "锦屏县", "剑河县", "台江县", "黎平县", "榕江县", "从江县",
+			"雷山县", "麻江县", "丹寨县"
+		]
+	}, {
+		"name": "黔南布依族苗族自治州",
+		"area": ["都匀市", "福泉市", "荔波县", "贵定县", "瓮安县", "独山县", "平塘县", "罗甸县", "长顺县", "龙里县", "惠水县", "三都水族自治县"]
+	}]
+}, {
+	"name": "云南省",
+	"city": [{
+		"name": "昆明市",
+		"area": ["市辖区", "五华区", "盘龙区", "官渡区", "西山区", "东川区", "呈贡区", "晋宁县", "富民县", "宜良县", "石林彝族自治县", "嵩明县",
+			"禄劝彝族苗族自治县", "寻甸回族彝族自治县", "安宁市"
+		]
+	}, {
+		"name": "曲靖市",
+		"area": ["市辖区", "麒麟区", "沾益区", "马龙县", "陆良县", "师宗县", "罗平县", "富源县", "会泽县", "宣威市"]
+	}, {
+		"name": "玉溪市",
+		"area": ["市辖区", "红塔区", "江川区", "澄江县", "通海县", "华宁县", "易门县", "峨山彝族自治县", "新平彝族傣族自治县", "元江哈尼族彝族傣族自治县"]
+	}, {
+		"name": "保山市",
+		"area": ["市辖区", "隆阳区", "施甸县", "龙陵县", "昌宁县", "腾冲市"]
+	}, {
+		"name": "昭通市",
+		"area": ["市辖区", "昭阳区", "鲁甸县", "巧家县", "盐津县", "大关县", "永善县", "绥江县", "镇雄县", "彝良县", "威信县", "水富县"]
+	}, {
+		"name": "丽江市",
+		"area": ["市辖区", "古城区", "玉龙纳西族自治县", "永胜县", "华坪县", "宁蒗彝族自治县"]
+	}, {
+		"name": "普洱市",
+		"area": ["市辖区", "思茅区", "宁洱哈尼族彝族自治县", "墨江哈尼族自治县", "景东彝族自治县", "景谷傣族彝族自治县", "镇沅彝族哈尼族拉祜族自治县",
+			"江城哈尼族彝族自治县", "孟连傣族拉祜族佤族自治县", "澜沧拉祜族自治县", "西盟佤族自治县"
+		]
+	}, {
+		"name": "临沧市",
+		"area": ["市辖区", "临翔区", "凤庆县", "云县", "永德县", "镇康县", "双江拉祜族佤族布朗族傣族自治县", "耿马傣族佤族自治县", "沧源佤族自治县"]
+	}, {
+		"name": "楚雄彝族自治州",
+		"area": ["楚雄市", "双柏县", "牟定县", "南华县", "姚安县", "大姚县", "永仁县", "元谋县", "武定县", "禄丰县"]
+	}, {
+		"name": "红河哈尼族彝族自治州",
+		"area": ["个旧市", "开远市", "蒙自市", "弥勒市", "屏边苗族自治县", "建水县", "石屏县", "泸西县", "元阳县", "红河县", "金平苗族瑶族傣族自治县",
+			"绿春县", "河口瑶族自治县"
+		]
+	}, {
+		"name": "文山壮族苗族自治州",
+		"area": ["文山市", "砚山县", "西畴县", "麻栗坡县", "马关县", "丘北县", "广南县", "富宁县"]
+	}, {
+		"name": "西双版纳傣族自治州",
+		"area": ["景洪市", "勐海县", "勐腊县"]
+	}, {
+		"name": "大理白族自治州",
+		"area": ["大理市", "漾濞彝族自治县", "祥云县", "宾川县", "弥渡县", "南涧彝族自治县", "巍山彝族回族自治县", "永平县", "云龙县", "洱源县", "剑川县",
+			"鹤庆县"
+		]
+	}, {
+		"name": "德宏傣族景颇族自治州",
+		"area": ["瑞丽市", "芒市", "梁河县", "盈江县", "陇川县"]
+	}, {
+		"name": "怒江傈僳族自治州",
+		"area": ["泸水市", "福贡县", "贡山独龙族怒族自治县", "兰坪白族普米族自治县"]
+	}, {
+		"name": "迪庆藏族自治州",
+		"area": ["香格里拉市", "德钦县", "维西傈僳族自治县"]
+	}]
+}, {
+	"name": "西藏自治区",
+	"city": [{
+		"name": "拉萨市",
+		"area": ["市辖区", "城关区", "堆龙德庆区", "林周县", "当雄县", "尼木县", "曲水县", "达孜县", "墨竹工卡县"]
+	}, {
+		"name": "日喀则市",
+		"area": ["桑珠孜区", "南木林县", "江孜县", "定日县", "萨迦县", "拉孜县", "昂仁县", "谢通门县", "白朗县", "仁布县", "康马县", "定结县",
+			"仲巴县", "亚东县", "吉隆县", "聂拉木县", "萨嘎县", "岗巴县"
+		]
+	}, {
+		"name": "昌都市",
+		"area": ["卡若区", "江达县", "贡觉县", "类乌齐县", "丁青县", "察雅县", "八宿县", "左贡县", "芒康县", "洛隆县", "边坝县"]
+	}, {
+		"name": "林芝市",
+		"area": ["巴宜区", "工布江达县", "米林县", "墨脱县", "波密县", "察隅县", "朗县"]
+	}, {
+		"name": "山南市",
+		"area": ["市辖区", "乃东区", "扎囊县", "贡嘎县", "桑日县", "琼结县", "曲松县", "措美县", "洛扎县", "加查县", "隆子县", "错那县", "浪卡子县"]
+	}, {
+		"name": "那曲地区",
+		"area": ["那曲县", "嘉黎县", "比如县", "聂荣县", "安多县", "申扎县", "索县", "班戈县", "巴青县", "尼玛县", "双湖县"]
+	}, {
+		"name": "阿里地区",
+		"area": ["普兰县", "札达县", "噶尔县", "日土县", "革吉县", "改则县", "措勤县"]
+	}]
+}, {
+	"name": "陕西省",
+	"city": [{
+		"name": "西安市",
+		"area": ["市辖区", "新城区", "碑林区", "莲湖区", "灞桥区", "未央区", "雁塔区", "阎良区", "临潼区", "长安区", "高陵区", "蓝田县", "周至县",
+			"户县"
+		]
+	}, {
+		"name": "铜川市",
+		"area": ["市辖区", "王益区", "印台区", "耀州区", "宜君县"]
+	}, {
+		"name": "宝鸡市",
+		"area": ["市辖区", "渭滨区", "金台区", "陈仓区", "凤翔县", "岐山县", "扶风县", "眉县", "陇县", "千阳县", "麟游县", "凤县", "太白县"]
+	}, {
+		"name": "咸阳市",
+		"area": ["市辖区", "秦都区", "杨陵区", "渭城区", "三原县", "泾阳县", "乾县", "礼泉县", "永寿县", "彬县", "长武县", "旬邑县", "淳化县",
+			"武功县", "兴平市"
+		]
+	}, {
+		"name": "渭南市",
+		"area": ["市辖区", "临渭区", "华州区", "潼关县", "大荔县", "合阳县", "澄城县", "蒲城县", "白水县", "富平县", "韩城市", "华阴市"]
+	}, {
+		"name": "延安市",
+		"area": ["市辖区", "宝塔区", "安塞区", "延长县", "延川县", "子长县", "志丹县", "吴起县", "甘泉县", "富县", "洛川县", "宜川县", "黄龙县",
+			"黄陵县"
+		]
+	}, {
+		"name": "汉中市",
+		"area": ["市辖区", "汉台区", "南郑县", "城固县", "洋县", "西乡县", "勉县", "宁强县", "略阳县", "镇巴县", "留坝县", "佛坪县"]
+	}, {
+		"name": "榆林市",
+		"area": ["市辖区", "榆阳区", "横山区", "神木县", "府谷县", "靖边县", "定边县", "绥德县", "米脂县", "佳县", "吴堡县", "清涧县", "子洲县"]
+	}, {
+		"name": "安康市",
+		"area": ["市辖区", "汉滨区", "汉阴县", "石泉县", "宁陕县", "紫阳县", "岚皋县", "平利县", "镇坪县", "旬阳县", "白河县"]
+	}, {
+		"name": "商洛市",
+		"area": ["市辖区", "商州区", "洛南县", "丹凤县", "商南县", "山阳县", "镇安县", "柞水县"]
+	}]
+}, {
+	"name": "甘肃省",
+	"city": [{
+		"name": "兰州市",
+		"area": ["市辖区", "城关区", "七里河区", "西固区", "安宁区", "红古区", "永登县", "皋兰县", "榆中县"]
+	}, {
+		"name": "嘉峪关市",
+		"area": ["市辖区"]
+	}, {
+		"name": "金昌市",
+		"area": ["市辖区", "金川区", "永昌县"]
+	}, {
+		"name": "白银市",
+		"area": ["市辖区", "白银区", "平川区", "靖远县", "会宁县", "景泰县"]
+	}, {
+		"name": "天水市",
+		"area": ["市辖区", "秦州区", "麦积区", "清水县", "秦安县", "甘谷县", "武山县", "张家川回族自治县"]
+	}, {
+		"name": "武威市",
+		"area": ["市辖区", "凉州区", "民勤县", "古浪县", "天祝藏族自治县"]
+	}, {
+		"name": "张掖市",
+		"area": ["市辖区", "甘州区", "肃南裕固族自治县", "民乐县", "临泽县", "高台县", "山丹县"]
+	}, {
+		"name": "平凉市",
+		"area": ["市辖区", "崆峒区", "泾川县", "灵台县", "崇信县", "华亭县", "庄浪县", "静宁县"]
+	}, {
+		"name": "酒泉市",
+		"area": ["市辖区", "肃州区", "金塔县", "瓜州县", "肃北蒙古族自治县", "阿克塞哈萨克族自治县", "玉门市", "敦煌市"]
+	}, {
+		"name": "庆阳市",
+		"area": ["市辖区", "西峰区", "庆城县", "环县", "华池县", "合水县", "正宁县", "宁县", "镇原县"]
+	}, {
+		"name": "定西市",
+		"area": ["市辖区", "安定区", "通渭县", "陇西县", "渭源县", "临洮县", "漳县", "岷县"]
+	}, {
+		"name": "陇南市",
+		"area": ["市辖区", "武都区", "成县", "文县", "宕昌县", "康县", "西和县", "礼县", "徽县", "两当县"]
+	}, {
+		"name": "临夏回族自治州",
+		"area": ["临夏市", "临夏县", "康乐县", "永靖县", "广河县", "和政县", "东乡族自治县", "积石山保安族东乡族撒拉族自治县"]
+	}, {
+		"name": "甘南藏族自治州",
+		"area": ["合作市", "临潭县", "卓尼县", "舟曲县", "迭部县", "玛曲县", "碌曲县", "夏河县"]
+	}]
+}, {
+	"name": "青海省",
+	"city": [{
+		"name": "西宁市",
+		"area": ["市辖区", "城东区", "城中区", "城西区", "城北区", "大通回族土族自治县", "湟中县", "湟源县"]
+	}, {
+		"name": "海东市",
+		"area": ["乐都区", "平安区", "民和回族土族自治县", "互助土族自治县", "化隆回族自治县", "循化撒拉族自治县"]
+	}, {
+		"name": "海北藏族自治州",
+		"area": ["门源回族自治县", "祁连县", "海晏县", "刚察县"]
+	}, {
+		"name": "黄南藏族自治州",
+		"area": ["同仁县", "尖扎县", "泽库县", "河南蒙古族自治县"]
+	}, {
+		"name": "海南藏族自治州",
+		"area": ["共和县", "同德县", "贵德县", "兴海县", "贵南县"]
+	}, {
+		"name": "果洛藏族自治州",
+		"area": ["玛沁县", "班玛县", "甘德县", "达日县", "久治县", "玛多县"]
+	}, {
+		"name": "玉树藏族自治州",
+		"area": ["玉树市", "杂多县", "称多县", "治多县", "囊谦县", "曲麻莱县"]
+	}, {
+		"name": "海西蒙古族藏族自治州",
+		"area": ["格尔木市", "德令哈市", "乌兰县", "都兰县", "天峻县"]
+	}]
+}, {
+	"name": "宁夏回族自治区",
+	"city": [{
+		"name": "银川市",
+		"area": ["市辖区", "兴庆区", "西夏区", "金凤区", "永宁县", "贺兰县", "灵武市"]
+	}, {
+		"name": "石嘴山市",
+		"area": ["市辖区", "大武口区", "惠农区", "平罗县"]
+	}, {
+		"name": "吴忠市",
+		"area": ["市辖区", "利通区", "红寺堡区", "盐池县", "同心县", "青铜峡市"]
+	}, {
+		"name": "固原市",
+		"area": ["市辖区", "原州区", "西吉县", "隆德县", "泾源县", "彭阳县"]
+	}, {
+		"name": "中卫市",
+		"area": ["市辖区", "沙坡头区", "中宁县", "海原县"]
+	}]
+}, {
+	"name": "新疆维吾尔自治区",
+	"city": [{
+		"name": "乌鲁木齐市",
+		"area": ["市辖区", "天山区", "沙依巴克区", "新市区", "水磨沟区", "头屯河区", "达坂城区", "米东区", "乌鲁木齐县"]
+	}, {
+		"name": "克拉玛依市",
+		"area": ["市辖区", "独山子区", "克拉玛依区", "白碱滩区", "乌尔禾区"]
+	}, {
+		"name": "吐鲁番市",
+		"area": ["高昌区", "鄯善县", "托克逊县"]
+	}, {
+		"name": "哈密市",
+		"area": ["伊州区", "巴里坤哈萨克自治县", "伊吾县"]
+	}, {
+		"name": "昌吉回族自治州",
+		"area": ["昌吉市", "阜康市", "呼图壁县", "玛纳斯县", "奇台县", "吉木萨尔县", "木垒哈萨克自治县"]
+	}, {
+		"name": "博尔塔拉蒙古自治州",
+		"area": ["博乐市", "阿拉山口市", "精河县", "温泉县"]
+	}, {
+		"name": "巴音郭楞蒙古自治州",
+		"area": ["库尔勒市", "轮台县", "尉犁县", "若羌县", "且末县", "焉耆回族自治县", "和静县", "和硕县", "博湖县"]
+	}, {
+		"name": "阿克苏地区",
+		"area": ["阿克苏市", "温宿县", "库车县", "沙雅县", "新和县", "拜城县", "乌什县", "阿瓦提县", "柯坪县"]
+	}, {
+		"name": "克孜勒苏柯尔克孜自治州",
+		"area": ["阿图什市", "阿克陶县", "阿合奇县", "乌恰县"]
+	}, {
+		"name": "喀什地区",
+		"area": ["喀什市", "疏附县", "疏勒县", "英吉沙县", "泽普县", "莎车县", "叶城县", "麦盖提县", "岳普湖县", "伽师县", "巴楚县",
+			"塔什库尔干塔吉克自治县"
+		]
+	}, {
+		"name": "和田地区",
+		"area": ["和田市", "和田县", "墨玉县", "皮山县", "洛浦县", "策勒县", "于田县", "民丰县"]
+	}, {
+		"name": "伊犁哈萨克自治州",
+		"area": ["伊宁市", "奎屯市", "霍尔果斯市", "伊宁县", "察布查尔锡伯自治县", "霍城县", "巩留县", "新源县", "昭苏县", "特克斯县", "尼勒克县"]
+	}, {
+		"name": "塔城地区",
+		"area": ["塔城市", "乌苏市", "额敏县", "沙湾县", "托里县", "裕民县", "和布克赛尔蒙古自治县"]
+	}, {
+		"name": "阿勒泰地区",
+		"area": ["阿勒泰市", "布尔津县", "富蕴县", "福海县", "哈巴河县", "青河县", "吉木乃县"]
+	}, {
+		"name": "直辖县",
+		"area": ["石河子市", "阿拉尔市", "图木舒克市", "五家渠市", "铁门关市"]
+	}]
+}, {
+	"name": "香港特别行政区",
+	"city": [{
+		"name": "香港特别行政区",
+		"area": ["中西区", "东区", "九龙城区", "观塘区", "南区", "深水埗区", "湾仔区", "黄大仙区", "油尖旺区", "离岛区", "葵青区", "北区", "西贡区",
+			"沙田区", "屯门区", "大埔区", "荃湾区", "元朗区"
+		]
+	}]
+}, {
+	"name": "澳门特别行政区",
+	"city": [{
+		"name": "澳门特别行政区",
+		"area": ["澳门半岛", "凼仔", "路凼城", "路环"]
+	}]
+}, {
+	"name": "台湾",
+	"city": [{
+		"name": "彰化县",
+		"area": ["芳苑乡", "芬园乡", "福兴乡", "和美镇", "花坛乡", "鹿港镇", "埤头乡", "埔心乡", "埔盐乡", "伸港乡", "社头乡", "田尾乡", "田中镇",
+			"线西乡", "溪湖镇", "秀水乡", "溪州乡", "永靖乡", "员林市", "竹塘乡"
+		]
+	}, {
+		"name": "新北市",
+		"area": ["八里区", "板桥区", "贡寮区", "金山区", "林口区", "芦洲区", "坪林区", "平溪区", "瑞芳区", "三重区", "三峡区", "三芝区", "深坑区",
+			"石碇区", "石门区", "双溪区", "树林区", "泰山区", "淡水区", "土城区"
+		]
+	}, {
+		"name": "澎湖县",
+		"area": ["白沙乡", "湖西乡", "马公市", "七美乡", "望安乡", "西屿乡"]
+	}, {
+		"name": "屏东县",
+		"area": ["三地门乡", "狮子乡", "泰武乡", "万丹乡", "万峦乡", "雾臺乡", "新埤乡", "新园乡", "盐埔乡", "竹田乡", "长治乡", "潮州镇", "车城乡",
+			"春日乡", "东港镇", "枋寮乡", "枋山乡", "高树乡", "恆春镇", "佳冬乡"
+		]
+	}, {
+		"name": "臺中市",
+		"area": ["梧栖区", "乌日区", "新社区", "西屯区", "北屯区", "中区", "大肚区", "大甲区", "大里区", "大雅区", "大安区", "东势区", "东区",
+			"丰原区", "和平区", "后里区", "龙井区", "南屯区", "北区", "清水区"
+		]
+	}, {
+		"name": "臺南市",
+		"area": ["佳里区", "将军区", "六甲区", "柳营区", "龙崎区", "麻豆区", "南化区", "楠西区", "北区", "七股区", "仁德区", "善化区", "山上区",
+			"南区", "中西区", "下营区", "西港区", "新化区", "新市区", "新营区"
+		]
+	}, {
+		"name": "臺北市",
+		"area": ["北投区", "大同区", "大安区", "南港区", "内湖区", "士林区", "松山区", "万华区", "文山区", "信义区", "中山区", "中正区"]
+	}, {
+		"name": "臺东县",
+		"area": ["卑南乡", "长滨乡", "成功镇", "池上乡", "达仁乡", "大武乡", "东河乡", "关山镇", "海端乡", "金峰乡", "兰屿乡", "绿岛乡", "鹿野乡",
+			"太麻里乡", "臺东市", "延平乡"
+		]
+	}, {
+		"name": "桃园市",
+		"area": ["八德区", "大溪区", "大园区", "復兴区", "观音区", "龟山区", "龙潭区", "芦竹区", "平镇区", "桃园区", "新屋区", "杨梅区", "中坜区"]
+	}, {
+		"name": "宜兰县",
+		"area": ["大同乡", "钓鱼臺", "冬山乡", "礁溪乡", "罗东镇", "南澳乡", "三星乡", "苏澳镇", "头城镇", "五结乡", "宜兰市", "员山乡", "壮围乡"]
+	}, {
+		"name": "南投县",
+		"area": ["草屯镇", "国姓乡", "集集镇", "鹿谷乡", "名间乡", "南投市", "埔里镇", "仁爱乡", "水里乡", "信义乡", "鱼池乡", "中寮乡", "竹山镇"]
+	}, {
+		"name": "南海岛",
+		"area": ["东沙群岛", "南沙群岛"]
+	}, {
+		"name": "苗栗县",
+		"area": ["头屋乡", "西湖乡", "苑里镇", "造桥乡", "竹南镇", "卓兰镇", "大湖乡", "公馆乡", "后龙镇", "苗栗市", "南庄乡", "三湾乡", "三义乡",
+			"狮潭乡", "泰安乡", "铜锣乡", "通霄镇", "头份市"
+		]
+	}, {
+		"name": "嘉义市",
+		"area": ["东区", "西区"]
+	}, {
+		"name": "嘉义县",
+		"area": ["阿里山乡", "布袋镇", "大林镇", "大埔乡", "东石乡", "番路乡", "六脚乡", "鹿草乡", "梅山乡", "民雄乡", "朴子市", "水上乡", "太保市",
+			"溪口乡", "新港乡", "义竹乡", "中埔乡", "竹崎乡"
+		]
+	}, {
+		"name": "新竹市",
+		"area": ["东区", "北区"]
+	}, {
+		"name": "新竹县",
+		"area": ["峨眉乡", "关西镇", "横山乡", "湖口乡", "尖石乡", "芎林乡", "五峰乡", "新丰乡", "新埔镇", "竹北市", "竹东镇", "宝山乡", "北埔乡"]
+	}, {
+		"name": "花莲县",
+		"area": ["卓溪乡", "丰滨乡", "凤林镇", "富里乡", "光復乡", "花莲市", "吉安乡", "瑞穗乡", "寿丰乡", "万荣乡", "新城乡", "秀林乡", "玉里镇"]
+	}, {
+		"name": "高雄市",
+		"area": ["阿莲区", "大寮区", "大社区", "大树区", "凤山区", "冈山区", "鼓山区", "湖内区", "甲仙区", "苓雅区", "林园区", "六龟区", "路竹区",
+			"茂林区", "美浓区", "弥陀区", "那玛夏区", "楠梓区", "内门区", "鸟松区"
+		]
+	}, {
+		"name": "基隆市",
+		"area": ["安乐区", "暖暖区", "七堵区", "仁爱区", "信义区", "中山区", "中正区"]
+	}, {
+		"name": "金门县",
+		"area": ["金城镇", "金湖镇", "金宁乡", "金沙镇", "烈屿乡", "乌坵乡"]
+	}, {
+		"name": "连江县",
+		"area": ["北竿乡", "东引乡", "莒光乡", "南竿乡"]
+	}, {
+		"name": "云林县",
+		"area": ["褒忠乡", "北港镇", "莿桐乡", "大埤乡", "东势乡", "斗六市", "斗南镇", "二崙乡", "古坑乡", "虎尾镇", "口湖乡", "林内乡", "崙背乡",
+			"麦寮乡", "水林乡", "四湖乡", "臺西乡", "土库镇", "西螺镇", "元长乡"
+		]
+	}]
+}]

+ 103 - 0
components/wangding-pickerAddress/wangding-pickerAddress.vue

@@ -0,0 +1,103 @@
+<template>
+	<picker @change="bindPickerChange" @columnchange="columnchange" :range="array" range-key="name" :value="value" mode="multiSelector">
+		<slot></slot>
+	</picker>
+</template>
+
+<script>
+	import AllAddress from './data.js'
+	let selectVal = ['','',''];
+	
+	export default {
+		data() {
+			return{
+				value: [0,0,0],
+				array: [],
+				index: 0
+			}
+		},
+		created() {
+			this.initSelect()
+		},
+		methods:{
+			// 初始化地址选项
+			initSelect() {
+				this.updateSourceDate() // 更新源数据
+				.updateAddressDate() // 更新结果数据
+				.$forceUpdate()  // 触发双向绑定
+			},
+			// 地址控件改变控件
+			columnchange(d) {
+				this.updateSelectIndex(d.detail.column, d.detail.value) // 更新选择索引
+				.updateSourceDate() // 更新源数据
+				.updateAddressDate() // 更新结果数据
+				.$forceUpdate()  // 触发双向绑定
+			},
+			
+			/**
+			 * 更新源数据
+			 * */
+			updateSourceDate() {
+				this.array = []
+				this.array[0] = AllAddress.map(obj => {
+					return {
+						name: obj.name
+					}
+				})
+				this.array[1] = AllAddress[this.value[0]].city.map(obj => {
+					return {
+						name: obj.name
+					}
+				})
+				this.array[2] = AllAddress[this.value[0]].city[this.value[1]].area.map(obj => { 
+					return {
+						name: obj
+					}
+				})
+				return this
+			},
+			
+			/**
+			 * 更新索引
+			 * */
+			updateSelectIndex(column, value){
+				let arr = JSON.parse(JSON.stringify(this.value)) 
+				arr[column] = value
+				if(column === 0 ) {
+					arr[1] = 0
+					arr[2] = 0
+				}
+				if(column === 1 ) {
+					arr[2] = 0
+				}
+				this.value = arr
+				return this
+			},
+			
+			/**
+			 * 更新结果数据 
+			 * */
+			updateAddressDate() {
+				selectVal[0] = this.array[0][this.value[0]].name
+				selectVal[1] = this.array[1][this.value[1]].name 
+				selectVal[2] = this.array[2][this.value[2]].name 
+				return this
+			},
+			
+			/**
+			 * 点击确定
+			 * */
+			bindPickerChange(e) {
+				this.$emit('change', {
+					index: this.value,
+					data: selectVal
+				})
+				return this
+			}
+			
+		}
+	}
+</script>
+
+<style>
+</style>

+ 33 - 0
index.html

@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+	<head>
+		<meta charset="utf-8">
+		<meta http-equiv="X-UA-Compatible" content="IE=edge">
+		<title>
+			<%= htmlWebpackPlugin.options.title %>
+		</title>
+		<!-- Open Graph data -->
+		<!-- <meta property="og:title" content="Title Here" /> -->
+		<!-- <meta property="og:url" content="http://www.example.com/" /> -->
+		<!-- <meta property="og:image" content="http://example.com/image.jpg" /> -->
+		<!-- <meta property="og:description" content="Description Here" /> -->
+		<script>
+		window.wx = null;
+		//uniapp默认的wx重置
+		</script>
+		<script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
+		<script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
+		<script>
+			var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
+			document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+		</script>
+		<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
+	</head>
+	<body>
+		<noscript>
+			<strong>Please enable JavaScript to continue.</strong>
+		</noscript>
+		<div id="app"></div>
+		<!-- built files will be auto injected -->
+	</body>
+</html>

+ 25 - 0
libs/i18n/index.js

@@ -0,0 +1,25 @@
+import vue from "vue";
+import VueI18n from "vue-i18n";
+vue.use(VueI18n)
+
+// 获取语言
+const requireComponent = require.context(
+    // 其组件目录的相对路径
+    './lang',
+    // 是否查询其子目录
+    true,
+    // 匹配基础组件文件名的正则表达式
+    /[a-zA-Z]\w+\.(json)$/
+)
+let messages = new Object();
+requireComponent.keys().forEach(fileName => {
+    // 获取组件的PascalCase命名
+    const componentName = fileName.split('/').pop().replace(/\.\w+$/, '');
+    messages[componentName] = requireComponent(fileName);
+})
+// 语言注入
+let i18n = new VueI18n({
+    locale: uni.getStorageSync('lang')||'tw',
+    messages: messages
+})
+export default i18n;

+ 556 - 0
libs/i18n/lang/cn.json

@@ -0,0 +1,556 @@
+{
+	"home":{
+		"d0": "首页",
+		"d1": "质押",
+		"d2": "互娱",
+		"d3": "资讯",
+		"d4": "我的"
+	},
+	"homepledge":{
+		"PKR介绍":"PKR介绍",
+		"description":"<p style='text-indent:2rem'>Polker(PKR)是第一款区块链在线兢猜游戏,它使用虚幻引擎4实现身临其境的强大游戏玩法,同时利用可证明的公平和TRNG系统实现真正透明的游戏玩法。PKR还使用已经获得专利和正在申请专利的技术,允许用户下注数+种加密货币,而无需将其持有的资产转换为单一支持的加密货币标准。POLKER 旨在在Substrate(Polkadot)上运行,近期上线PancakeSwap尽情期待。</p>",
+		"体验场":"体验场",
+		"自由场":"自由场",
+		"游戏流程":"游戏流程",
+		"合作伙伴":"合作伙伴",
+		"活跃用户":"活跃用户",
+		"累计返奖":"累计返奖",
+		"总用户":"总用户",
+		"链接钱包":"链接钱包",
+		"m1":"我的质押",
+		"m0":"质押项目",
+		"m2":"起投",
+		"m3":"天",
+		"total": "总额",
+		"a4": "日均收益率",
+		"a5": "立即加入"
+	},
+	"indexenter":{
+		"第":"第",
+		"期":"期",
+		"距离结束": "距离结束",
+		"结果":"结果",
+		"大": "大",
+		"小": "小",
+		"奇": "奇",
+		"偶": "偶",
+		"竞猜总额": "竞猜总额",
+		"本场累计":"本场累计",
+		"确认":"确认",
+		"清空":"清空",
+		"近期记录":"近期记录",
+		"确定":"确定",
+		"取消":"取消",
+		"期号":"期号",
+		"竞猜数":"竞猜数",
+		"竞猜值":"竞猜值"
+	},
+	"recharge":{
+		"请输入充值金额":"请输入充值金额",
+		"立即充值":"立即充值",
+		"申请失败":"申请失败"
+	},
+	"withdrawal":{
+		"暂未开放":"暂未开放"
+	},
+	"homeinformation":{
+		"m1":"互娱玩法介绍",
+		"m0":"互娱游戏推广计划",
+		"m2":"互娱游戏举例",
+		"m4": "项目亮点",
+		"m5": "趣味性强,简单易懂,一学就会",
+		"m6": "资金随进随出",
+		"m7": "以小博大",
+		"m8": "只赚不赔",
+		"m9": "流水收益大"
+	},
+	"zy":{
+		"a1": "单笔上限",
+		"m0":"日均收益率",
+		"m1":"限投份额",
+		"m2":"托管过期",
+		"m3": "单笔上限",
+		"m4": "起投金额",
+		"m5": "收益过程",
+		"m6": "申请提交",
+		"m7": "今日",
+		"m8": "每日返利",
+		"m9": "24小时后",
+		"m10": "申请提现",
+		"m11": "24小时之内到账",
+		"m12": "加入后不可撤销",
+		"m13": "产品到期选择复投,收益不断",
+		"m14": "收益公式",
+		"m15": "收益结算",
+		"m16": "加入金额(元)",
+		"m17": "余额",
+		"m18": "当前可用",
+		"m19": "立即加入",
+		"b1": "押注金额",
+		"b2": "请输入购买金额",
+		"b3": "确定",
+		"b4": "取消",
+		"b5": "请输入数字",
+		"b6": "质押成功"
+	},
+	"user":{
+		"c1": "余额",
+		"a4": "累計",
+		"a7": "充值",
+		"a6": "提现",
+		"a8":"累计收益",
+		"a9":"个人交易总量",
+		"a10":"团队交易总量",
+		"b1":"我的工具",
+		"b2":"余额明细",
+		"b3":"开奖记录",
+		"b4":"会员列表",
+		"b5":"分享链接",
+		"b6":"在线留言",
+		"b7":"交易密码",
+		"b8":"退出登录",
+		"b9":"设置",
+		"a1":"统计表",
+		"a2": "联系客服"
+	},
+	"myple": {
+		"u1": "质押数",
+		"u2": "进行中",
+		"u3": "已结束",
+		"u4": "质押金额",
+		"u5": "累计收益",
+		"u6": "质押期限",
+		"u7": "购买时间",
+		"u8": "到期时间"
+	},
+	"enter": {
+		"u1": "下单金额",
+		"u2": "单期最高",
+		"u4": "小",
+		"u5": "奇",
+		"u6": "大",
+		"u7": "偶",
+		"u8": "距离结束",
+		"u9": "订单列表",
+		"u10": "历史列表",
+		"u11": "币种",
+		"u12": "金额",
+		"u13": "盈亏",
+		"u14": "进度",
+		"u15": "余额",
+		"u16": "去充值",
+		"u17": "已完成",
+		"u18": "详情",
+		"u19": "秒",
+		"u20": "5分线",
+		"a9": "请输入数量",
+		"b3": "请输入6位交易密码",
+		"c4": "温馨提示",
+		"b5": "您未登录!是否马上登录?",
+		"a2": "未开奖",
+		"a3": "活动未开启,请等待活动开启",
+		"a4": "进行中",
+		"a5": "中奖",
+		"a6": "未中奖",
+		"a7": "提示",
+		"a8": "是否押注",
+		"a10": "到"
+	},
+	"userinfo": {
+		"u1": "收款地址",
+		"u2": "保存相冊",
+		"u3": "复制地址",
+		"u4": "链名称",
+		"u5": "提示:充值大于5000U,请先充值一笔小额的,到账之后再进行大额充值。充值地址每个人都是唯一的!请一定要仔细确认避免充错!",
+		"u6": "提币类型",
+		"u7": "提币地址",
+		"u8": "提币数量",
+		"u9": "提现须知",
+		"u10": "使用步骤",
+		"u11": "输入您要提现的币种、地址、数量,点击“下一步”",
+		"u12": "确认资讯无误后输入资金密码完成验证,点击“确认提现”",
+		"u13": "每日提现上限2次;",
+		"u14": "提现成功后,提现地址将自动保存以便于下次使用;",
+		"u15": "请注意每个人的地址都是唯一的,请一定要仔细确认避免提错!",
+		"u16": "申请提币",
+		"u17": "请输入提币地址",
+		"u18": "请输入体现数量",
+		"u19": "余额",
+		"u20": "全部",
+		"u21": "手续费",
+		"u22": "余额不足",
+		"u23": "提交中",
+		"u24": "申请成功",
+		"u25": "申请失败!请联系客服"
+	},
+	"money": {
+		"a1": "钱包",
+		"a2": "我的余额",
+		"a3": "充值",
+		"a4": "提现",
+		"a5": "累计收入",
+		"a6": "累计支出",
+		"a7": "历史充值",
+		"a8": "历史提现"
+	},
+	"gameList": {
+		"a1": "待开奖",
+		"a2": "k线类型",
+		"a3": "5分线",
+		"a4": "互娱金额",
+		"a5": "开奖时间",
+		"a6": "已开奖",
+		"a7": "押注类型",
+		"a8": "获得奖金",
+		"a9": "开奖结果",
+		"a10": "开奖數字"
+	},
+	"huiyuan": {
+		"a1": "直推人数",
+		"a2": "团队人数",
+		"a3": "账户总数",
+		"a4": "有效账户",
+		"a5": "详情",
+		"a6": "互娱金额",
+		"a7": "推广数",
+		"b1": "长按保存图片",
+		"b2": "保存海报",
+		"b3": "邀请您进入绿津",
+		"b4": "保存成功",
+		"b5": "您已拒绝获取相册权限",
+		"b6": "是否进入权限管理,调整授权?",
+		"b7": "已取消!",
+		"b8": "保存成功!",
+		"b9": "保存图片成功",
+		"b0": "获取中"
+	},
+	"password": {
+		"a1": "修改交易密码",
+		"a2": "新密码",
+		"a3": "请输入新密码",
+		"a4": "重复密码",
+		"a5": "请重复输入密码",
+		"a6": "验证码",
+		"a7": "请输入验证码",
+		"a8": "确认"
+	},
+	"introduce": {
+		"a1": "五分钟一期",
+		"a6": "两分钟一期",
+		"a2": "互娱区",
+		"a3": "压和值(11~18)大,(3~10)小,(3,5,7,9.11,13,15,17)单,(4,6,8,10,12,14,16,18)双,压100U中180U",
+		"a4": "共享区",
+		"a5": "压和值(11~18)大,(3~10)小,(3,5,7,911,13,15,17)单,(4,6,8,10,12,14,16,18)双,压100U中100.2U,没中返本金。共享区每天2小时,每晚19点-21点,5分钟一场。"
+	},
+	"promotion": {
+		"a1": "推广计划",
+		"a2": "会员",
+		"a3": "充值100U就是有效会员",
+		"a4": "推荐2个有效会员,互娱区流水1%,共享区流水0.01%",
+		"a5": "推荐3个有效会员,其中2个V1,互娱流水1.5%,共享区流水0.015%",
+		"a6": "推荐4个有效会员,其中2个V2,互娱流水2%,共享区流水0.02%",
+		"a7": "推荐5个有效会员,其中2个V3,互娱流水2.5%,共享区流水0.025%",
+		"a8": "推荐6个有效会员,其中2个V4,互娱流水3%,共享区流水0.03%",
+		"a9": "推荐7个有效会员,其中2个V5,互娱流水3.5%,共享区流水0.035%",
+		"a10": "推荐8个有效会员,其中2个V6,互娱流水4%,共享区流水0.04%",
+		"a11": "推荐9个有效会员,其中2个V7,互娱流水5%,共享区流水0.05%",
+		"a12": "平级奖",
+		"a13": "直推流水收益的10%"
+	},
+	"game": {
+		"a1": "游戏举例",
+		"a2": "举例",
+		"a3": "充值10000U",
+		"a4": "共享区下注5000U,中5010U,一天有2小时,24期可压如果中12期就有120U的收益 共享区没中返本金",
+		"a5": "流水",
+		"a6": "如V1级別,流水5000U*24期=120000U的流水*0.00001=12U流水的收益如V8级別,流水5000U*24期=120000U的流水*0.0005=60U流水的收益互娱区流水更大"
+	},
+	"set": {
+		"a1": "头像",
+		"a2": "昵称",
+		"a3": "账号",
+		"a4": "修改",
+		"a5": "提交",
+		"a6": "退出",
+		"a7": "第",
+		"a8": "期"
+	},
+	"tab": {
+		"a1": "我的质押",
+		"a2": "历史列表",
+		"a3": "充值",
+		"a4": "玩法介绍",
+		"a5": "推广计划",
+		"a6": "游戏举例",
+		"a7": "设置",
+		"a8": "奖励提现",
+		"a9": "互娱记录",
+		"b1": "会员列表",
+		"b2": "分享链接",
+		"b3": "忘记密码",
+		"b4": "修改资料",
+		"b5": "质押详情"
+	},
+	
+	"add": {
+		"kt": "Airdrop",
+		"ck": "deposit",
+		"a1": "选择付款方式",
+		"a2": "Line",
+		"a3":"付款数量",
+		"a4":"认购数量",
+		"a5":"信用评分"
+	},
+	"miao": {
+		"a1": "秒合约",
+		"a2": "做多",
+		"a3": "做空",
+		"a4": "选择到期时间",
+		"a5": "买入数量",
+		"a6": "手续费",
+		"a7": "可用USDT",
+		"a8": "下单成功",
+		"b1": "购买记录",
+		"b2": "做多",
+		"b3": "做空",
+		"b4": "下单价(元)",
+		"b5": "交易金额",
+		"b6": "预计收益率",
+		"b7": "交易周期",
+		"b8": "结束价",
+		"b9": "超时反馈",
+		"b10": "倒计时"
+	},
+	
+	"common": {
+		"submit": "提交",
+		"success": "成功",
+		"tips": "温馨提示",
+		"total": "总额",
+		"type": "类型",
+		"copy": "复制",
+		"light": "白",
+		"dark": "黑",
+		"service": "客服",
+		"toDwon": "是否前往下载页",
+		"a0": "请输入申购码",
+		"a1": "复制成功",
+		"a2": "复制失败",
+		"a3": "申购记录",
+		"a4": "支付金额",
+		"a5": "到账数量",
+		"a6": "账号",
+		"a7": "充值数量",
+		"cancelButtonText": "取消",
+		"confirmButtonText": "确认"
+	},
+	"base": {
+		"a0": "标题",
+		"a1": "返回",
+		"a2": "更多",
+		"a9": "最新价",
+		"b0": "涨跌幅",
+		"b3": "请登录",
+		"c5": "提币地址",
+		"c8": "添加成功",
+		"c9": "取消成功",
+		"d0": "首页",
+		"d1": "交易",
+		"d2": "资产",
+		"d3": "请输入搜索关键词",
+		"e6": "矿工等级",
+		"e7": "矿工",
+		"e8": "APP",
+		"g8": "价格",
+		"g9": "涨幅",
+		"h0": "已绑定"
+	},
+	
+	"accountSettings": {
+		"a0": "账号设置",
+		"a1": "头像",
+		"a2": "昵称",
+		"a3": "主账号",
+		"a4": "手机号",
+		"a5": "解绑",
+		"a6": "绑定",
+		"a7": "邮箱绑定",
+		"a8": "切换账户",
+		"a9": "退出登录",
+		"b0": "修改昵称",
+		"b1": "请输入昵称",
+		"b2": "语言"
+	},
+	
+	"option": {
+		"a0": "期权",
+		"a1": "距离交割",
+		"a2": "看多",
+		"a3": "看空",
+		"a4": "收益率",
+		"a5": "购买",
+		"a6": "多",
+		"a7": "空",
+		"a8": "当前",
+		"a9": "下期",
+		"b0": "看平",
+		"b1": "涨幅选择",
+		"b2": "收益率",
+		"b3": "购买数量",
+		"b4": "请输入数量",
+		"b5": "余额",
+		"b6": "预计收益",
+		"b7": "立即购买",
+		"b8": "涨",
+		"b9": "平",
+		"c0": "跌",
+		"c1": "购买成功",
+		"c2": "详情",
+		"c3": "订单号",
+		"c4": "开盘价",
+		"c5": "收盘价",
+		"c6": "买入时间",
+		"c7": "买入数量",
+		"c8": "购买类型",
+		"c9": "状态",
+		"d0": "交割结果",
+		"d1": "结算数量",
+		"d2": "交割时间",
+		"d3": "查看更多",
+		"d4": "购买期权",
+		"d5": "等待交割",
+		"d6": "我的交割",
+		"d7": "交割记录",
+		"d8": "分钟",
+		"d9": "小时",
+		"d10": "分时",
+		"e0": "天",
+		"e1": "周",
+		"e2": "月",
+		"e3": "方向",
+		"e4": "涨跌幅",
+		"e5":"请输入1000~6000",
+		"e6":"请输入10000-30000",
+		"e7":"请输入60000-100000",
+		"e8":"请输入200000-300000",
+		"e9":"请输入600000-1000000",
+		"e10":"请输入超过3,000,000"
+		
+	},
+	
+	"reg": {
+		"a0": "手机注册",
+		"a1": "邮箱注册",
+		"a2": "手机",
+		"a3": "请输入手机号",
+		"a4": "邮箱",
+		"a5": "请输入邮箱号",
+		"a6": "验证码",
+		"a7": "请输入验证码",
+		"a8": "密码",
+		"a9": "请输入密码",
+		"b0": "确认密码",
+		"b1": "请确认密码",
+		"b2": "推荐人",
+		"b3": "请输入推荐人",
+		"b4": "选填",
+		"b5": "您已同意",
+		"b6": "用户协议",
+		"b7": "并了解我们的",
+		"b8": "隐私协议",
+		"b9": "注册",
+		"c0": "已有账号?",
+		"c1": "立即登录",
+		"c2": "请阅读并同意协议",
+		"c3": "请填写手机号",
+		"c4": "请填写邮箱号",
+		"c5": "注册成功",
+		"c6": "验证码"
+	},
+	"safe": {
+		"a0": "解绑",
+		"a1": "绑定",
+		"a2": "邮箱",
+		"a3": "邮箱号",
+		"a4": "请输入邮箱号",
+		"a5": "邮箱验证码",
+		"a6": "请输入验证码",
+		"a7": "验证码",
+		"a8": "解绑成功",
+		"a9": "绑定成功",
+		"b0": "忘记登录密码",
+		"b1": "账号",
+		"b2": "请输入手机/邮箱号",
+		"b3": "新密码",
+		"b4": "请输入新密码",
+		"b5": "确认密码",
+		"b6": "请确认密码",
+		"b7": "确认修改",
+		"b8": "请输入正确的手机号",
+		"b9": "谷歌验证器",
+		"c0": "操作方法:下载并打开谷歌验证器,扫描下方二维码或手动输入秘钥添加验证令牌。",
+		"c1": "复制密钥",
+		"c2": "我已经妥善保存密钥,丢失后将不可找回。",
+		"c3": "下一步",
+		"c4": "短信验证码",
+		"c5": "谷歌验证码",
+		"c6": "确认绑定",
+		"c7": "安全中心",
+		"c8": "登录密码",
+		"c9": "修改",
+		"d0": "设置",
+		"d1": "修改交易密码",
+		"d2": "手机",
+		"d3": "修改成功",
+		"d4": "手机号",
+		"d5": "请输入手机号",
+		"d6": "请输入短信验证码",
+		"d7": "关闭",
+		"d8": "开启",
+		"d9": "验证",
+		"e0": "短信",
+		"e1": "关闭成功",
+		"e2": "开启成功",
+		"e3": "确认",
+		"e4": "设置成功",
+		"f1":"密码和确认密码不匹配",
+		"f2":"验证码错误",
+		"f3": "请输入自己的账户",
+		"f4": "申请注销成功,请耐心等待审核",
+		"f5": "密码修改成功",
+		"f6": "个人资料",
+		"f7": "修改登录密码"
+	},
+	"login": {
+		"a0": "PKR",
+		"a1": "请输入手机号/邮箱",
+		"a2": "密码",
+		"a3": "请输入密码",
+		"a4": "登录",
+		"a5": "忘记密码",
+		"a6": "没有账号",
+		"a7": "立即注册",
+		"a8": "手机",
+		"a9": "邮箱",
+		"b0": "完成",
+		"b2": "忘记密码?",
+		"b3": "请输入交易密码",
+		"b4": "请输入邀请码",
+		"b5": "发送验证码",
+		"b6": "请输入验证码",
+		"b7": "确定要退出登录吗?",
+		"b8": "忘记支付密码?",
+		"b9": "请输入正确的邮箱地址",
+		"c2": "无法在微信中下载,请用浏览器打开下载",
+		"c3": "注册成功是否登录?",
+		"c4": "下期压注",
+		"c5": "当期进行",
+		"c6": "请再次输入密码",
+		"c7": "两次密码不正确",
+		"c8": "请输入邮箱号码",
+		"c9": "请输入正确的邮箱或手机",
+		"c10": "验证码已发送"
+		
+	}
+	
+}

+ 649 - 0
libs/i18n/lang/en.json

@@ -0,0 +1,649 @@
+{
+	"home":{
+		"d0": "Home",
+		"d1": "Pledge",
+		"d2": "Game",
+		"d3": "News",
+		"d4": "My"
+	},
+	"homepledge":{
+		"PKR介绍":"PKR description",
+		"description":"<p style='text-indent:2rem'>Polker (PKR) is the first blockchain online quiz game that uses Unreal Engine 4 to achieve immersive and powerful gameplay, while leveraging provable fairness and TRNG systems to achieve truly transparent gameplay.</p><p style='text-indent:2rem'>PKR also uses patented and patent-pending technology that allows users to bet on multiple cryptocurrencies without having to convert their assets into a single supported cryptocurrency standard.</p><p style='text-indent:2rem'>POLKER is designed to run on Substrate (Polkadot), aiming to support the next generation of virtual reality with stunning 3D characters, visual effects, and environments.</p>",
+		"体验场":"experience",
+		"自由场":"free field",
+		"游戏流程":"Game flow",
+		"合作伙伴":"Partner companies",
+		"活跃用户":"Active Users",
+		"累计返奖":"All Reward",
+		"总用户":"Total users",
+		"链接钱包":"Link wallet",
+		"m1":"My pledge",
+		"m0":"Pledge Game",
+		"m2":"Start",
+		"m3":"Day",
+		"total": "Total",
+		"a4": "Daily profit",
+		"a5": "Buy"
+	},
+	"indexenter":{
+		"第":"No.",
+		"期":"",
+		"距离结束": "Distance End",
+		"结果":"End",
+		"大": "big",
+		"小": "small",
+		"奇": "odd",
+		"偶": "even",
+		"竞猜总额": "Total amount of guess",
+		"本场累计":"Cumulative amount of this game",
+		"确认":"confirm",
+		"清空":"Empty it",
+		"近期记录":"History",
+		"押注记录":"Betting",
+		"确定":"confirm",
+		"取消":"cancel",
+		"期号":"No",
+		"竞猜数":"Guess",
+		"竞猜值":"Guessing value"
+	},
+	"recharge":{
+		"请输入充值金额":"Please enter the recharge amount",
+		"立即充值":"Recharge immediately",
+		"申请失败":"Application failed"
+	},
+	"withdrawal":{
+		"暂未开放":"Not yet open"
+	},
+	"zy":{
+		"m0":"Daily return",
+		"m1":"Limited",
+		"m2":"Expire",
+		"m3": "Upper limit",
+		"m4": "Sum money",
+		"m5": "Return process",
+		"m6": "Submit ",
+		"m7": "Today",
+		"m8": "Daily rebate",
+		"m9": "After 24 hours",
+		"m10": "Withdrawal",
+		"m11": "Received within 24 hours",
+		"m12": "Not revocable after joining",
+		"m13": "Mature reinvestment with continuous returns",
+		"m14": "Income formula",
+		"m15": "Income settlement",
+		"m16": "Amount added(yuan)",
+		"m17": "Balance",
+		"m18": "Total",
+		"m19": "Join Now",
+		"b1": "Bet amount",
+		"b2": "Please enter the amount",
+		"b3": "Confirm",
+		"b4": "Cancel",
+		"b5": "Please enter a number",
+		"b6": "Pledge successful"
+	},
+	"homeinformation":{
+		"m1":"Game Introduction",
+		"m0":"Promotion Plan",
+		"m2":"Examples of games",
+		"m4": "Project Highlights",
+		"m5": "Highly interesting, easy to understand, and easy to learn",
+		"m6": "Funds come in and go out as needed",
+		"m7": "Throw a sprat to catch a herring",
+		"m8": "Only earn without losing",
+		"m9": "Large flow income"
+	},
+	"userinfo": {
+		"u1": "Collection",
+		"u2": "Save",
+		"u3": "Copy",
+		"u4": "Name",
+		"u5": " Note: If the recharge amount is greater than 5000U, please recharge a small amount first, and then proceed with the large amount recharge after it is credited. The recharge address is unique for each person! Please be sure to double-check and avoid recharging to the wrong address!",
+	    "u6": "Cash withdrawal type",
+	    "u7": "Cash withdrawal address",
+	    "u8": "Cash withdrawal count",
+		"u9": "Withdrawal Notice",
+		"u10": "Usage steps",
+		"u11": "Enter the currency, address, and amount you want to withdraw, and click Next",
+		"u12": "After confirming the information is correct, enter your fund password for verification, and click Confirm Withdrawal",
+		"u13": "Daily withdrawal limit: 2 times;",
+		"u14": "After successful withdrawal, the withdrawal address will be automatically saved for future use",
+		"u15": "Please note that each person’s address is unique. Please be sure to double-check and avoid withdrawing to the wrong address!",
+		"u16": "Confirm",
+		"u17": " Please enter the withdrawal address",
+		"u18": "Please enter the reflected quantity",
+		"u19": "Balance",
+		"u20": "All",
+		"u21": "Handling fee",
+		"u22": "Insufficient balance",
+		"u23": "Submitting",
+		"u24": "Application successful",
+		"u25": "Application failed! Please contact customer service"
+	},	
+	"myple": {
+		"u1": "Number of pledges",
+		"u2": "Progress",
+		"u3": "Ended",
+		"u4": "Amount",
+		"u5": "Income",
+		"u6": "Term",
+		"u7": "Buying",
+		"u8": "Expiration"
+	},
+	"enter": {
+		"u1": "Order amount",
+		"u2": "Highest",
+		"u3": "K types",
+		"u4": "Dowm",
+		"u5": "Strange",
+		"u6": "Up",
+		"u7": "Image",
+		"u8": "Distance End",
+		"u9": "Order",
+		"u10": "History",
+		"u11": "Currency",
+		"u12": "Amount",
+		"u13": "Status",
+		"u14": "Schedule",
+		"u15": "Balance",
+		"u16": "Recharge",
+		"u17": "Finished",
+		"u18": "Details",
+		"u19": "S",
+		"u20": "Quincle",
+		"a9": "Please enter the amount",
+		"b3": "Please enter a transaction password",
+		"c4": "Note",
+		"b5": "Please log in",
+		"a2": "Unlicensed",
+		"a3": "The activity has not been opened, please wait",
+		"a4": "Ongoing",
+		"a5": "Winning",
+		"a6": "Nothing",
+		"a7": "Prompt",
+		"a8": "Whether to bet",
+		"a10": "To"
+	},
+	"money": {
+		"a1": "wallet",
+		"a2": "My Balance",
+		"a3": "Recharge",
+		"a4": "Withdrawal",
+		"a5": "Accumulated income",
+		"a6": "Accumulated expenses",
+		"a7": "Historical recharge",
+		"a8": "Historical withdrawal"
+	},	
+	"gameList": {
+		"a1": "Await",
+		"a2": "k types",
+		"a3": "5-point line",
+		"a4": "Game amount",
+		"a5": "Lottery opening time",
+		"a6": "Awarded",
+		"a7": "Bet type",
+		"a8": " Return amount",
+		"a9": "Lottery results",
+		"a10": "Number"
+	},
+	"huiyuan": {
+		"a1": "Recommends",
+		"a2": "Teams",
+		"a3": "Total accounts",
+		"a4": "Valid Account",
+		"a5": "Details",
+		"a6": "amount",
+		"a7": "Promotions",
+		"b1": "Long press to save image",
+		"b2": "Save poster",
+		"b3": "Inviting you to enter Lvjin",
+		"b4": "Successfully saved",
+		"b5": "You have refused to obtain album permissions",
+		"b6": " Do you want to enter permission management and adjust authorization",
+		"b7": "Canceled!",
+		"b8": "Successfully saved!",
+		"b9": "Image saved successfully",
+		"b0": "Obtaining"
+	},
+	"password": {
+		"a1": "Change transaction password",
+		"a2": "New password",
+		"a3": "New password",
+		"a4": "Repeat ",
+		"a5": "Repeat the password",
+		"a6": "Code",
+		"a7": "Please enter code",
+		"a8": "Confirm"
+	},
+	"user":{
+		"c1": "Balance",
+		"a4": "All ",
+		"a7": "recharge",
+		"a6": "withdrawal",
+		"a8":"Gross earnings",
+		"a9":"Personal transaction volume",
+		"a10":"Team transaction volume",
+		"b1":"My Tools",
+		"b2":"Balance details",
+		"b3":"Game log",
+		"b4":"Member List",
+		"b5":"Share Link",
+		"b6":"Online Message",
+		"b7":"Transaction password",
+		"b8":"Exit",
+		"b9":"Set",
+		"a1":"Statistical Table",
+		"a2": "Customer Service"
+	},
+	"introduce": {
+		"a1": "five minute installment",
+		"a2": "Mutual entertainment area",
+		"a3": "Pressure sum (11-18) is large, (3-10) is small, (3,5,7,9,11,13,15,17) is single, (4,6,8,10,12,14,16,18) is double, 100U in pressure, 195U in pressure",
+		"a4": "Share area",
+		"a5": "The pressure sum (11-18) is large, (3-10) is small, (3,5,7,9,11,13,15,17) is single, (4,6,8,10,12,14,16,18) is double, pressure 100U is 100.2U, if not, the principal will be returned.The sharing area is 2 hours a day, from 19:00 to 21:00 every night, with a 5-minute game.",
+		"a6": "One minute installment"
+	},
+	"promotion": {
+		"a1": "Campaign",
+		"a2": "member",
+		"a3": "Recharging 100U is a valid member",
+		"a4": "Recommend 2 valid members, 1% Mutual entertainment field flow, and 0.01% share field flow",
+		"a5": "Recommend 3 valid members, of which 2 are V1, with 1.5% Mutual entertainment flowing water and 0.015% share field flowing water",
+		"a6": "Recommend 4 valid members, including 2 V2, 2% Mutual entertainment flowing water, and 0.02% share field flowing water",
+		"a7": "Recommend 5 valid members, including 2 V3 members, 2.5% Mutual entertainment flowing water, and 0.025% share field flowing water",
+		"a8": "Recommend 6 valid members, including 2 V4 members with 2.8% Mutual entertainment flowing water and 0.03% share field flowing water",
+		"a9": "Recommend 7 valid members, including 2 V5 members, 3.1% Mutual entertainment flowing water, and 0.035% share field flowing water",
+		"a10": "Recommend 8 valid members, including 2 V6, 3.4% Mutual entertainment flowing water, and 0.04% share field flowing water",
+		"a11": "Recommend 9 valid members, including 2 V7 members, 3.7% Mutual entertainment flowing water, and 0.05% share field flowing water",
+		"a12": "Peer level award",
+		"a13": "10% of direct flow revenue"
+	},
+	"game": {
+		"a1": "Game examples",
+		"a2": "Example",
+		"a3": "Recharge 10000U",
+		"a4": "Experience Field Bet 5000U, Medium 5010U, 2 hours per day, 24 installments available for pressure. If 12 installments are available, there will be 120U of returns. Experience Field does not refund principal",
+		"a5": "Flowing water",
+		"a6": "For example, at V1 level, the return on flow of 5000U * 24 periods=120000U flow * 0.0001=12U flow, as at V8 level, the return on flow of 5000U * 24 periods=120000U flow * 0.0005=60U flow is greater in the Mutual entertainment field flow"
+	},
+	"set": {
+		"a1": "Avatar",
+		"a2": "Nickname",
+		"a3":"Login ID",
+		"a4":"Revise",
+		"a5":"Submit",
+		"a6":"Exit",
+		"a7": "No.",
+		"a8": ""
+	},
+	"tab": {
+		"a1": "My Pledge",
+		"a2": "History List",
+		"a3":"Recharge",
+		"a4":"Introduction game",
+		"a5":"Promotion Plan",
+		"a6":"Game examples",
+		"a7":"Settings",
+		"a8":"Reward withdrawal",
+		"a9":"Entertainment Record",
+		"b1": "Member List",
+		"b2": "Share Link",
+		"b3":"Forgot password",
+		"b4":"Modify data",
+		"b5": "Pledge Details"
+	},
+	
+	"add": {
+		"kt": "Airdrop",
+		"ck": "deposit",
+		"a1": "Select payment method",
+		"a2": "Line",
+		"a3":"Payment amount",
+		"a4":"Quantity Purchased",
+		"a5":"Credit Rating"
+	},
+	"miao": {
+		"a1": "Quick Futures",
+		"a2": "Long",
+		"a3": "Short",
+		"a4": "Select due time",
+		"a5": "Buy Amount",
+		"a6": "Fee",
+		"a7": "Available USDT",
+		"a8": "Order placed successfully",
+		"b1": "Order History",
+		"b2": "Long",
+		"b3": "Short",
+		"b4": "Order Price ($)",
+		"b5": "Transaction Amount",
+		"b6": "Profit (%)",
+		"b7": "Time Period",
+		"b8": "Closing Price",
+		"b9": "Profit or loss",
+		"b10": "Countdown"
+	},
+	
+	
+	"common": {
+		"error1": "Your account is abnormal, please contact customer service",
+		"D": "Day",
+		"M": "Month",
+		"Y": "Year",
+		"add": "Add",
+		"address": "Address",
+		"all": "All",
+		"amout": "Amount",
+		"cancel": "Cancel",
+		"check": "Check",
+		"code": "Verification Code",
+		"confirm": "Confirm",
+		"date": "Date",
+		"detail": "Detail",
+		"email": "Mailbox",
+		"enter": "Please enter",
+		"error": "Failed",
+		"getCode": "Get Verification Code",
+		"h": "Hour",
+		"loadMore": "Load More",
+		"m": "Minute",
+		"money": "Amount",
+		"more": "More",
+		"notData": "No data temporarily",
+		"notMore": "No More",
+		"phone": "Mobile",
+		"requestError": "The network is busy, please try again later",
+		"s": "second",
+		"save": "Save",
+		"select": "Please select",
+		"sendSuccess": "Send successfully",
+		"sms": "SMS",
+		"submit": "Submit",
+		"success": "Success",
+		"tips": "Note",
+		"total": "Total",
+		"type": "Type",
+		"copy": "Copy",
+		"light": "light",
+		"dark": "dark",
+		"service": "Customer Service",
+		"toDwon": "Do you want to go to the download page",
+		"a0": "Please enter the purchase code",
+		"a1": "Copy succeeded",
+		"a2": "copy failed",
+		"a3": "Presale History",
+		"a4": "Payment amount",
+		"a5": "Quantity received",
+		"a6": "account number",
+		"a7": "Recharge quantity",
+		"a8": "Payment voucher",
+		"a9": "Please input recharge quantity",
+		"b0": "Please upload the payment voucher",
+		"b1": "purchase{amount}Pieces{name}Token available{rate}%reward",
+		"b2": "Subscription activities",
+		"cancelButtonText": "Cancel",
+		"confirmButtonText": "Confirm"
+	},
+	"base": {
+		"a0": "Title",
+		"a1": "Return",
+		"a2": "More",
+		"a3": "Quotes",
+		"a4": "Options",
+		"a5": "Tap a new zone",
+		"a6": "Member",
+		"a7": "College",
+		"a8": "Trading Pair",
+		"a9": "Latest Price",
+		"b0": "Rise and fall",
+		"b1": "Click to log in",
+		"b2": "Welcome to",
+		"b3": "Please log in",
+		"b4": "Upgrade",
+		"b5": "Deposit",
+		"b6": "Withdraw",
+		"b7": "Referral",
+		"b8": "Deduct the handling fee",
+		"b9": "Available",
+		"c0": "Buy",
+		"c1": "My Order",
+		"c2": "Identity Verification",
+		"c3": "Security",
+		"c4": "Notifications",
+		"c5": "Address Book",
+		"c6": "Account",
+		"c7": "Favourites",
+		"c8": "Added successfully",
+		"c9": "Cancelled successfully",
+		"d0": "Home",
+		"d1": "Transaction",
+		"d2": "Assets",
+		"d3": "Please enter search keywords",
+		"d4": "All",
+		"d5": "Motherboard",
+		"d6": "Total assets converted",
+		"d7": "Spot Account",
+		"d8": "Transfer",
+		"d9": "Search Pair",
+		"e0": "Hide",
+		"e1": "Balance Assets",
+		"e2": "Frozen/Locked",
+		"e3": "Est. Value",
+		"e4": "Futures Account",
+		"e5": "Contract conversion",
+		"e6": "Miner Level",
+		"e7": "Miner",
+		"e8": "APP",
+		"e9": "Sign in",
+		"f0": "Sign in now",
+		"f1": "Check in every day",
+		"f2": "If you check in for 7 consecutive days, you will get extra gifts",
+		"f3": "buy crypto",
+		"f4": "ETH Layer2",
+		"f5": "Referral",
+		"f6": "Reward automatic delivery",
+		"f7": "If you break the contract, you will not be rewarded",
+		"f8": "24H Turnover",
+		"f9": "Charitable Fund",
+		"g1": "Convert",
+		"g2": "About Us",
+		"g3": "Version 6.0.7",
+		"g4": "Help Center",
+		"g5": "Unbound",
+		"g6": "Language",
+		"g7": "Pair",
+		"g8": "Last Price",
+		"g9": "Change",
+		"h0": "Bound",
+		"h1": "Maintenance updating",
+		"h2": "Perpetual contract"
+	},
+	
+	"accountSettings": {
+		"a0": "My Profile",
+		"a1": "Profile Photo",
+		"a2": "Nickname",
+		"a3": "Main Account",
+		"a4": "Phone",
+		"a5": "Untie",
+		"a6": "Binding",
+		"a7": "Email",
+		"a8": "Change Account",
+		"a9": "Logout",
+		"b0": "Modify Nickname",
+		"b1": "Please enter a nickname",
+		"b2": "Language"
+	},
+	
+	
+	
+	"option": {
+		"a0": "Options",
+		"a1": "Deadline",
+		"a2": "Call Options",
+		"a3": "Put Options",
+		"a4": "Yield",
+		"a5": "Buy",
+		"a6": "Multi",
+		"a7": "Empty",
+		"a8": "Current",
+		"a9": "Next Issue",
+		"b0": "Vol",
+		"b1": "Increase selection",
+		"b2": "Profit",
+		"b3": "Purchase amount",
+		"b4": "Please enter the amount",
+		"b5": "Balance",
+		"b6": "Estimated Income",
+		"b7": "Buy Now",
+		"b8": "Call",
+		"b9": "Vol",
+		"c0": "Put",
+		"c1": "Successful purchase",
+		"c2": "Details",
+		"c3": "Transaction Number",
+		"c4": "Opening Price",
+		"c5": "Closing Price",
+		"c6": "Deal Time",
+		"c7": "Buy Amount",
+		"c8": "Purchase Type",
+		"c9": "Status",
+		"d0": "Delivery Result",
+		"d1": "Settlement Amount",
+		"d2": "Delivery Time",
+		"d3": "View more",
+		"d4": "Buy Options",
+		"d5": "Deliveries in process",
+		"d6": "My delivered",
+		"d7": "Delivery History",
+		"d8": "Minutes",
+		"d9": "Hour",
+		"d10": "Time",
+		"e0": "Day",
+		"e1": "Week",
+		"e2": "Month",
+		"e3": "Direction",
+		"e4": "Rise and fall",
+		"e5":"Please input 1000-6000",
+		"e6":"Please input 10000-30000",
+		"e7":"Please input 60000-100000",
+		"e8":"Please input 200000-300000",
+		"e9":"Please input 600000-1000000",
+		"e10":"Over 3,000,000"
+	},
+	
+	"reg": {
+		"a0": "Register by Phone Number",
+		"a1": "Register by Email",
+		"a2": "Mobile",
+		"a3": "Please enter your phone number",
+		"a4": "Email",
+		"a5": "Please enter your Email",
+		"a6": "Verification Code",
+		"a7": "Please enter the verification code",
+		"a8": "Password",
+		"a9": "Please enter a password",
+		"b0": "Confirm Password",
+		"b1": "Please confirm your password",
+		"b2": "Referral ID",
+		"b3": "Please enter your referrer ID",
+		"b4": "Optional",
+		"b5": "I have read and agree to the",
+		"b6": "User Agreement",
+		"b7": "and",
+		"b8": "Privacy Agreement",
+		"b9": "Register",
+		"c0": "Already have a DWF’s account?",
+		"c1": "Login",
+		"c2": "Please read and agreeto the agreement",
+		"c3": "Please fill in the phone number",
+		"c4": "Please fill in the mailbox number",
+		"c5": "Registered successfully",
+		"c6": "Code"
+	},
+	
+	"safe": {
+		"a0": "Remove",
+		"a1": "Bind",
+		"a2": "Email",
+		"a3": "Mailbox Number",
+		"a4": "Please enter the mailbox number",
+		"a5": "Email Verification Code",
+		"a6": "Please enter the verification code",
+		"a7": "Verification Code",
+		"a8": "Unbind successfully",
+		"a9": "Binding successful",
+		"b0": "Forgot password",
+		"b1": "Phone number or email address",
+		"b2": "Please enter your phone number or email address",
+		"b3": "New Password",
+		"b4": "Please enter a new password",
+		"b5": "Confirm Password",
+		"b6": "Please confirm your password",
+		"b7": "Change Password",
+		"b8": "Please enter the correct phone number",
+		"b9": "Google Authenticator",
+		"c0": "How to do: Download and open Google Authenticator, scan the QR code below or manually enter the secret key to add a verification token.",
+		"c1": "Copy key",
+		"c2": "I have stored the key properly, and it will not be retrieved if it is lost.",
+		"c3": "Next",
+		"c4": "SMS verification code",
+		"c5": "Google Verification Code",
+		"c6": "Confirm binding",
+		"c7": "Security",
+		"c8": "Login Password",
+		"c9": "Modify",
+		"d0": "Settings",
+		"d1": "Transaction Password",
+		"d2": "Phone Number",
+		"d3": "Modified successfully",
+		"d4": "Mobile Number",
+		"d5": "Please enter your phone number",
+		"d6": "Please enter the SMS verification code",
+		"d7": "Close",
+		"d8": "Open",
+		"d9": "Verify",
+		"e0": "SMS",
+		"e1": "Closed successfully",
+		"e2": "Open successfully",
+		"e3": "Confirm",
+		"e4": "Set up successfully",
+		"f1":"Password & Confirm Password don’t match",
+		"f2":"Wrong verification code",
+		"f3": "Please enter your own account",
+		"f4": "Successfully applied for cancellation, please wait",
+		"f5": "Password modification successful",
+		"f6": "Personal Information",
+		"f7": "Change Password"
+	},
+	
+	"login": {
+		"a0": "PKR",
+		"a1": "Please enter phone number/mailbox",
+		"a2": "Password",
+		"a3": "Please enter a password",
+		"a4": "Login",
+		"a5": "Forgot Password",
+		"a6": "No account",
+		"a7": "Register Now",
+		"a8": "Mobile",
+		"a9": "Email",
+		"b0": "Done",
+		"b2": "Fotgot password?",
+		"b3": "Please enter a transaction password",
+		"b4": "Please enter a invitation code",
+		"b5": "Send code",
+		"b6": "Please enter code",
+		"b7": "Are you sure you want to log out",
+		"b8": "Forgot payment password?",
+		"b9": "Please enter the correct email address",
+		"c2": "Unable to download on WeChat. Please open the download using your browser",
+		"c3": "Successfully registered, do you want to log in?",
+		"c4": "Next",
+		"c5": "Current",
+		"c6": "Please enter the password again",
+		"c7": "Incorrect password twice",
+		"c8": "Please enter your email number",
+		"c9": "Please enter the correct email or phone number",
+		"c10": "Verification code sent"
+	}
+}

+ 646 - 0
libs/i18n/lang/tw.json

@@ -0,0 +1,646 @@
+{
+	"home":{
+		"d0": "首頁",
+		"d1": "質押",
+		"d2": "互娛",
+		"d3": "資訊",
+		"d4": "我的"
+		},
+	"homepledge":{
+		"PKR介绍":"PKR介绍",
+		"description":"<p style='text-indent:2rem'>Polker(PKR)是第一款区块链在线兢猜游戏,它使用虚幻引擎4实现身临其境的强大游戏玩法,同时利用可证明的公平和TRNG系统实现真正透明的游戏玩法。PKR还使用已经获得专利和正在申请专利的技术,允许用户下注数+种加密货币,而无需将其持有的资产转换为单一支持的加密货币标准。POLKER 旨在在Substrate(Polkadot)上运行,近期上线PancakeSwap尽情期待。</p>"	,
+		"体验场":"體驗場",
+		"自由场":"自由場",
+		"游戏流程":"遊戲流程",
+		"合作伙伴":"合作夥伴",
+		"活跃用户":"活躍用戶",
+		"累计返奖":"累計返獎",
+		"总用户":"總用戶",
+		"链接钱包":"連結錢包",
+		"m1":"我的質押",
+		"m0":"質押項目",
+		"m2":"起投",
+		"m3":"天",
+		"total": "總額",
+		"a4": "日均收益率",
+		"a5": "立即加入"
+	},
+	"indexenter":{
+		"第":"第",
+		"期":"期",
+		"距离结束": "距離結束",
+		"结果":"結果",
+		"大": "大",
+		"小": "小",
+		"奇": "奇",
+		"偶": "偶",
+		"竞猜总额": "競猜總額",
+		"本场累计":"本場累計",
+		"确认":"確認",
+		"清空":"清空",
+		"近期记录":"近期記錄",
+		"押注记录":"押注記錄",
+		"确定":"確定",
+		"取消":"取消",
+		"期号":"期號",
+		"竞猜数":"競猜數",
+		"竞猜值":"競猜值"
+	},
+	"recharge":{
+		"请输入充值金额":"請輸入充值金額",
+		"立即充值":"立即充值",
+		"申请失败":"申請失敗"
+	},
+	"withdrawal":{
+		"暂未开放":"暫未開放"
+	},
+	"homeinformation":{
+		"m1":"互娛遊戲玩法介紹",
+		"m0":"互娛遊戲推廣計劃",
+		"m2":"互娛遊戲舉例",
+		"m4": "項目亮點",
+		"m5": "趣味性強,簡單易 懂,一學就會",
+		"m6": "資金隨進隨出",
+		"m7": "以小博大",
+		"m8": "只賺不賠",
+		"m9": "流水收益大"
+	},
+	"zy":{
+		"m0":"日均收益率",
+		"m1":"限投份額",
+		"m2":"託管週期",
+		"m3": "單筆上限",
+		"m4": "起投金額",
+		"m5": "收益過程",
+		"m6": "申請提交",
+		"m7": "今日",
+		"m8": "每日返利",
+		"m9": "24小時後",
+		"m10": "申請提現",
+		"m11": "24小時之內到賬",
+		"m12": "買入後不可撤銷",
+		"m13": "产品到期选择复投,收益不断",
+		"m14": "收益公式",
+		"m15": "收益結算",
+		"m16": "買入金額(元)",
+		"m17": "餘額",
+		"m18": "當前可用",
+		"m19": "立即加入",
+		"b1": "押注金额",
+		"b2": "请输入购买金额",
+		"b3": "确定",
+		"b4": "取消",
+		"b5": "请输入数字",
+		"b6": "质押成功"
+	},
+	"user":{
+		"c1": "餘額",
+		"a4": "累計",
+		"a7": "充值",
+		"a6": "提現",
+		"a8":"累計收益",
+		"a9":"個人交易總量",
+		"a10":"團隊交易總量",
+		"b1":"我的工具",
+		"b2":"餘額明細",
+		"b3":"開獎記錄",
+		"b4":"會員列表",
+		"b5":"分享鏈接",
+		"b6":"在線留言",
+		"b7":"交易密碼",
+		"b8":"退出登錄",
+		"ck": "存款",
+		"b9": "设置",
+		"a1": "統計表",
+		"a2": "聯系客服"
+	},
+	"myple": {
+		"u1": "質押數",
+		"u2": "进行中",
+		"u3": "已结束",
+		"u4": "質押金額",
+		"u5": "累計收益",
+		"u6": "質押期限",
+		"u7": "購買時間",
+		"u8": "到期時間"
+	},
+	"enter": {
+		"u1": "下單金額",
+		"u2": "單期最高",
+		"u3": "k線類型",
+		"u4": "大",
+		"u5": "奇",
+		"u6": "小",
+		"u7": "偶",
+		"u8": "距離結束",
+		"u9": "訂單列表",
+		"u10": "歷史列表",
+		"u11": "幣種",
+		"u12": "金額",
+		"u13": "盈虧",
+		"u14": "進度",
+		"u15": "餘額",
+		"u16": "去充值",
+		"u17": "已完成",
+		"u18": "詳情",
+		"u19": "秒",
+		"u20": "5分線",
+		"a9": "請輸入數量",
+		"b3": "請輸入6位交易密碼",
+		"c4": "溫馨提示",
+		"b5": "您未登錄,是否立即登錄?",
+		"a2": "未開獎",
+		"a3": "活動未開啟,請等待活動開啟",
+		"a4": "進行中",
+		"a5": "中獎",
+		"a6": "未中獎",
+		"a7": "提示",
+		"a8": "是否押注",
+		"a10": "到"
+	},
+	"userinfo": {
+		"u1": "收款地址",
+		"u2": "保存相冊",
+		"u3": "複製地址",
+		"u4": "鏈名稱",
+		"u5": "提示:充值大於5000U,請先充值一筆小額的,到賬之後再進行大額充值。充值地址每個人都是唯一的!請一定要仔細確認避免充錯!",
+		"u6": "提幣類型",
+		"u7": "提幣地址",
+		"u8": "提幣數量",
+		"u9": "提現須知",
+		"u10": "使用步驟",
+		"u11": "輸入您要提現的幣種、地址、數量,點擊“下一步”",
+		"u12": "確認資訊無誤後輸入資金密碼完成驗證,點擊“確認提現”",
+		"u13": "每日提現上限2次;",
+		"u14": "提現成功後,提現地址將自動保存以便於下次使用;",
+		"u15": "請注意每個人的地址都是唯一的,請一定要仔細確認避免提錯!",
+		"u16": "申請提幣",
+		"u17": "請輸入提幣地址",
+		"u18": "請輸入體現數量",
+		"u19": "余額",
+		"u20": "全部",
+		"u21": "手續費",
+		"u22": "余額不足",
+		"u23": "提交中",
+		"u24": "申請成功",
+		"u25": "申請失敗!請聯系客服"
+	},
+	"money": {
+		"a1": "錢包",
+		"a2": "我的餘額",
+		"a3": "充值",
+		"a4": "提現",
+		"a5": "累计收入",
+		"a6": "累计支出",
+		"a7": "历史充值",
+		"a8": "历史提現"
+	},
+	"gameList": {
+		"a1": "待開獎",
+		"a2": "k線類型",
+		"a3": "5分線",
+		"a4": "互娛金額",
+		"a5": "開獎時間",
+		"a6": "已開獎",
+		"a7": "押註類型",
+		"a8": "獲得獎金",
+		"a9": "開獎結果",
+		"a10": "開獎數字"
+	},
+	"huiyuan": {
+		"a1": "直推人數",
+		"a2": "團隊人數",
+		"a3": "賬戶總數",
+		"a4": "有效賬戶",
+		"a5": "詳情",
+		"a6": "互娛金額",
+		"a7": "推廣數",
+		"b1": "長按保存圖片",
+		"b2": "保存海報",
+		"b3": "邀請您進入綠津",
+		"b4": "保存成功",
+		"b5": "您已拒絕獲取相冊權限",
+		"b6": "是否進入權限管理,調整授權?",
+		"b7": "已取消!",
+		"b8": "保存成功!",
+		"b9": "保存圖片成功",
+		"b0": "獲取中"
+	},
+	"password": {
+		"a1": "修改交易密碼",
+		"a2": "新密碼",
+		"a3": "請輸入新密碼",
+		"a4": "重復密碼",
+		"a5": "請重復輸入密碼",
+		"a6": "驗證碼",
+		"a7": "請輸入驗證碼",
+		"a8": "確認"
+	},
+	"introduce": {
+		"a1": "五分鐘一期",
+		"a2": "互娛區",
+		"a3": "壓和值 (11~18) 大,(3~10) 小,(3,5,7,9.11,13,15,17)單,(4,6,8,10,12,14,16,18)雙,壓100U中195U",
+		"a4": "共享區",
+		"a5": "壓和值 (11~18) 大,(3~10) 小,(3,5,7,911,13,15,17)單,(4,6,8,10,12,14,16,18)雙,壓100U中100.2U,没中返本金。共享區每天2小时,每晚19點-21點,5分鐘一场。",
+		"a6": "一分鐘一期"
+	},
+	"promotion": {
+		"a1": "推廣計劃",
+		"a2": "會員",
+		"a3": "充值100U就是有效會員",
+		"a4": "推薦2個有效會員,互娛區流水1%,共享區流水0.01%",
+		"a5": "推薦3個有效會員,其中2個V1,互娛區流水1.5%,共享區流水0.015%",
+		"a6": "推薦4個有效會員,其中2個V2,互娛區流水2%,共享區流水0.02%",
+		"a7": "推薦5個有效會員,其中2個V3,互娛區流水2.5%,共享區流水0.025%",
+		"a8": "推薦6個有效會員,其中2個V4,互娛區流水2.8%,共享區流水0.03%",
+		"a9": "推薦7個有效會員,其中2個V5,互娛區流水3.1%,共享區流水0.035%",
+		"a10": "推薦8個有效會員,其中2個V6,互娛區流水3.4%,共享區流水0.04%",
+		"a11": "推薦9個有效會員,其中2個V7,互娛區流水3.7%,共享區流水0.05%",
+		"a12": "平級獎",
+		"a13": "直推流水收益的10%"
+	},
+	"game": {
+		"a1": "共享區",
+		"a2": "舉例",
+		"a3": "充值10000U",
+		"a4": "共享區下注5000U,中5010U,一天有2小時,24期可壓如果中12期就有120U的收益 共享區沒中返本金",
+		"a5": "流水",
+		"a6": "如V1級別,流水5000U*24期=120000U的流水*0.0001=12U流水的收益如V8級別,流水5000U*24期=120000U的流水*0.0005=60U流水的收益互娛區流水更大"
+	},
+	"set": {
+		"a1": "頭像",
+		"a2": "昵稱",
+		"a3": "賬號",
+		"a4": "修改",
+		"a5":"提交",
+		"a6":"退出",
+		"a7": "第",
+		"a8": "期"
+	},
+
+	"tab": {
+		"a1": "我的質押",
+		"a2": "曆史列表",
+		"a3": "充值",
+		"a4": "玩法介紹",
+		"a5": "推廣計劃",
+		"a6": "遊戲舉例",
+		"a7": "設置",
+		"a8": "獎勵提現",
+		"a9": "互娛記錄",
+		"b1": "會員列表",
+		"b2": "分享鏈接",
+		"b3": "忘記密碼",
+		"b4": "修改資料",
+		"b5": "質押詳情"
+	},
+	"add": {
+		"ck": "存款",
+		"kt": "空投",
+		"a1": "選擇支付方式",
+		"a2": "Line",
+		"a3": "付款數量",
+		"a4": "認購數量",
+		"a5": "信用評分"
+	},
+	"miao": {
+		"a1": "秒合約",
+		"a2": "做多",
+		"a3": "做空",
+		"a4": "選擇到期時間",
+		"a5": "買入數量",
+		"a6": "手續費",
+		"a7": "可用USDT",
+		"a8": "下單成功",
+		"b1": "購買記錄",
+		"b2": "做多",
+		"b3": "做空",
+		"b4": "下單價格(元)",
+		"b5": "交易金額",
+		"b6": "預計收益率",
+		"b7": "交易週期",
+		"b8": "結束價格",
+		"b9": "逾期回報",
+		"b10": "倒數計時"
+	},
+	
+	"common": {
+		"error1": "您的賬號異常,請聯繫客服人員",
+		"D": "日",
+		"M": "月",
+		"Y": "年",
+		"add": "添加",
+		"address": "地址",
+		"all": "所有",
+		"amout": "數量",
+		"cancel": "取消",
+		"check": "審核",
+		"code": "驗證碼",
+		"confirm": "確定",
+		"date": "日期",
+		"detail": "詳情",
+		"email": "郵箱",
+		"enter": "請輸入",
+		"error": "失敗",
+		"getCode": "獲取驗證碼",
+		"h": "時",
+		"loadMore": "加載更多",
+		"m": "分",
+		"money": "金額",
+		"more": "更多",
+		"notData": "暫無數據",
+		"notMore": "沒有更多了",
+		"phone": "手機",
+		"requestError": "網絡繁忙,請稍後再試",
+		"s": "秒",
+		"save": "保存",
+		"select": "請選擇",
+		"sendSuccess": "發送成功",
+		"sms": "短信",
+		"submit": "提交",
+		"success": "成功",
+		"tips": "溫馨提示",
+		"total": "總額",
+		"type": "類型",
+		"copy": "複製",
+		"light": "白",
+		"dark": "黑",
+		"service": "客服",
+		"toDwon": "是否前往下載頁",
+		"a0": "請輸入申購碼",
+		"a1": "複製成功",
+		"a2": "複製失敗",
+		"a3": "申購記錄",
+		"a4": "支付金額",
+		"a5": "到賬數量",
+		"a6": "帳號",
+		"a7": "充值數量",
+		"a8": "支付憑證",
+		"a9": "請輸入充值數量",
+		"b0": "請上傳支付憑證",
+		"b1": "購買{amount}枚{name}代幣可獲{rate}%獎勵",
+		"b2": "申購活動",
+		"cancelButtonText": "取消",
+		"confirmButtonText": "確認"
+	},
+	"base": {
+		"a0": "標題",
+		"a1": "返回",
+		"a2": "更多",
+		"a3": "行情",
+		"a4": "期權",
+		"a5": "打新專區",
+		"a6": "會員",
+		"a7": "學院",
+		"a8": "交易對",
+		"a9": "最新價",
+		"b0": "漲跌幅",
+		"b1": "點擊登錄",
+		"b2": "歡迎來到",
+		"b3": "請登錄",
+		"b4": "升級",
+		"b5": "充幣",
+		"b6": "提幣",
+		"b7": "推廣",
+		"b8": "抵扣手續費",
+		"b9": "可用",
+		"c0": "購買",
+		"c1": "我的委託",
+		"c2": "身份認證",
+		"c3": "安全中心",
+		"c4": "消息通知",
+		"c5": "提幣地址",
+		"c6": "設置",
+		"c7": "自選",
+		"c8": "添加成功",
+		"c9": "取消成功",
+		"d0": "首頁",
+		"d1": "交易",
+		"d2": "資產",
+		"d3": "請輸入搜索關鍵詞",
+		"d4": "全部",
+		"d5": "主板",
+		"d6": "總資產折合",
+		"d7": "資金賬戶",
+		"d8": "劃轉",
+		"d9": "搜索幣種",
+		"e0": "隱藏",
+		"e1": "餘額資產",
+		"e2": "凍結",
+		"e3": "折合",
+		"e4": "合約賬戶",
+		"e5": "合約折合",
+		"e6": "礦工等級",
+		"e7": "礦工",
+		"e8": "APP",
+		"e9": "簽到",
+		"f0": "立即簽到",
+		"f1": "每天簽到獲得",
+		"f2": "連續簽到7天則額外贈送",
+		"f3": "買幣",
+		"f4": "ETH Layer2",
+		"f5": "邀請獎勵",
+		"f6": "獎勵自動派送",
+		"f7": "如果中斷簽到 則不可獲得獎勵",
+		"f8": "24H量",
+		"f9": "捐款",
+		"g1": "閃兌",
+		"g2": "關於我們",
+		"g3": "版本6.0.7",
+		"g4": "幫助中心",
+		"g5": "未綁定",
+		"g6": "語言切換",
+		"g7": "交易對",
+		"g8": "價格",
+		"g9": "漲幅",
+		"h0": "已綁定",
+		"h1": "維護更新中",
+		"h2": "永續合約"
+	},
+	
+	"accountSettings": {
+		"a0": "賬號設置",
+		"a1": "頭像",
+		"a2": "暱稱",
+		"a3": "主賬號",
+		"a4": "手機號",
+		"a5": "解綁",
+		"a6": "綁定",
+		"a7": "郵箱綁定",
+		"a8": "切換賬戶",
+		"a9": "退出登錄",
+		"b0": "修改暱稱",
+		"b1": "請輸入暱稱",
+		"b2": "語言"
+	},
+	
+	"option": {
+		"a0": "期權",
+		"a1": "距離交割",
+		"a2": "看多",
+		"a3": "看空",
+		"a4": "收益率",
+		"a5": "購買",
+		"a6": "多",
+		"a7": "空",
+		"a8": "當前",
+		"a9": "下期",
+		"b0": "看平",
+		"b1": "漲幅選擇",
+		"b2": "收益率",
+		"b3": "購買數量",
+		"b4": "請輸入數量",
+		"b5": "餘額",
+		"b6": "預計收益",
+		"b7": "立即購買",
+		"b8": "漲",
+		"b9": "平",
+		"c0": "跌",
+		"c1": "購買成功",
+		"c2": "詳情",
+		"c3": "訂單號",
+		"c4": "開盤價",
+		"c5": "收盤價",
+		"c6": "買入時間",
+		"c7": "買入數量",
+		"c8": "購買類型",
+		"c9": "狀態",
+		"d0": "交割結果",
+		"d1": "結算數量",
+		"d2": "交割時間",
+		"d3": "查看更多",
+		"d4": "購買期權",
+		"d5": "等待交割",
+		"d6": "我的交割",
+		"d7": "交割記錄",
+		"d8": "分鐘",
+		"d9": "小時",
+		"d10": "分時",
+		"e0": "天",
+		"e1": "週",
+		"e2": "月",
+		"e3": "方向",
+		"e4": "漲跌幅",
+		"e5":"請輸入1000~6000",
+		"e6":"請輸入10000-30000",
+		"e7":"請輸入60000-100000",
+		"e8":"請輸入200000-300000",
+		"e9":"請輸入600000-1000000",
+		"e10":"請輸入超過3,000,000"
+	},
+	
+	"reg": {
+		"a0": "手機註冊",
+		"a1": "郵箱註冊",
+		"a2": "手機",
+		"a3": "請輸入手機號",
+		"a4": "郵箱",
+		"a5": "請輸入郵箱號",
+		"a6": "驗證碼",
+		"a7": "請輸入驗證碼",
+		"a8": "密碼",
+		"a9": "請輸入密碼",
+		"b0": "確認密碼",
+		"b1": "請確認密碼",
+		"b2": "推薦人",
+		"b3": "請輸入推薦人",
+		"b4": "選填",
+		"b5": "您已同意",
+		"b6": "用戶協議",
+		"b7": "並了解我們的",
+		"b8": "隱私協議",
+		"b9": "註冊",
+		"c0": "已有賬號?",
+		"c1": "立即登錄",
+		"c2": "請閱讀並同意協議",
+		"c3": "請填寫手機號",
+		"c4": "請填寫郵箱號",
+		"c5": "註冊成功",
+		"c6": "驗證碼"
+	},
+	"safe": {
+		"a0": "解綁",
+		"a1": "綁定",
+		"a2": "郵箱",
+		"a3": "郵箱號",
+		"a4": "請輸入郵箱號",
+		"a5": "郵箱驗證碼",
+		"a6": "請輸入驗證碼",
+		"a7": "驗證碼",
+		"a8": "解綁成功",
+		"a9": "綁定成功",
+		"b0": "忘記登錄密碼",
+		"b1": "賬號",
+		"b2": "請輸入手機/郵箱號",
+		"b3": "新密碼",
+		"b4": "請輸入新密碼",
+		"b5": "確認密碼",
+		"b6": "請確認密碼",
+		"b7": "確認修改",
+		"b8": "請輸入正確的手機號",
+		"b9": "谷歌驗證器",
+		"c0": "操作方法:下載並打開谷歌驗證器,掃描下方二維碼或手動輸入秘鑰添加驗證令牌。",
+		"c1": "複製密鑰",
+		"c2": "我已經妥善保存密鑰,丟失後將不可找回。",
+		"c3": "下一步",
+		"c4": "短信驗證碼",
+		"c5": "谷歌驗證碼",
+		"c6": "確認綁定",
+		"c7": "安全中心",
+		"c8": "登錄密碼",
+		"c9": "修改",
+		"d0": "設置",
+		"d1": "修改交易密碼",
+		"d2": "手機",
+		"d3": "修改成功",
+		"d4": "手機號",
+		"d5": "請輸入手機號",
+		"d6": "請輸入短信驗證碼",
+		"d7": "關閉",
+		"d8": "開啟",
+		"d9": "驗證",
+		"e0": "短信",
+		"e1": "關閉成功",
+		"e2": "開啟成功",
+		"e3": "確認",
+		"e4": "設置成功",
+		"f1":"密碼和確認密碼不匹配",
+		"f2":"驗證碼錯誤",
+		"f3": "請輸入自己的賬戶",
+		"f4": "申請註銷成功,請耐心等待審核",
+		"f5": "密碼修改成功",
+		"f6": "個人資料",
+		"f7": "修改登录密碼"
+	},
+	
+	"login": {
+		"a0": "PKR",
+		"a1": "請输入手機號/郵箱",
+		"a2": "密碼",
+		"a3": "請輸入密碼",
+		"a4": "登錄",
+		"a5": "忘記密碼",
+		"a6": "沒有賬號",
+		"a7": "立即註冊",
+		"a8": "手機",
+		"a9": "郵箱",
+		"b0": "完成",
+		"b2": "忘记密码?",
+		"b3": "請輸入交易密碼",
+		"b4": "請輸入邀請碼",
+		"b5": "发送驗證碼",
+		"b6": "請輸入驗證碼",
+		"b7": "確定要退出登錄嗎?",
+		"b8": "忘記支付密碼?",
+		"b9": "請輸入正確的郵箱地址",
+		"c2": "無法在微信中下載,請用瀏覽器打開下載",
+		"c3": "註冊成功是否登錄?",
+		"c4": "下期壓注",
+		"c5": "當期進行",
+		"c6": "請再次輸入密碼",
+		"c7": "兩次密碼不正確",
+		"c8": "請輸入郵箱號碼",
+		"c9": "請輸入正確的郵箱或手機",
+		"c10": "驗證碼已發送"
+	}
+}

+ 39 - 0
libs/log.js

@@ -0,0 +1,39 @@
+
+const logLength=100;//缓存存储上限
+const name = 'log';//缓存名字
+export function addLog (data,content='') {
+	let log = uni.getStorageSync(name)||[];
+	log.unshift({
+		title:data,
+		content:content
+	});
+	uni.setStorageSync(name,log);
+	initLog(log);
+}
+
+
+export function delLog () {
+	return uni.setStorageSync(name,'');
+}
+
+export function getLog () {
+	return uni.getStorageSync(name);
+}
+
+export function initLog (log) {
+	if(log.length>logLength){
+		const newarr = log.slice(log.length-logLength);
+		uni.setStorageSync(name,newarr);
+	}
+}
+export function showLog (log) {
+	
+	let str = '';
+	uni.getStorageSync(name).forEach((e) => {
+		str+=e.title+':'+JSON.stringify(e.content)
+	})
+	uni.showModal({
+		title:"日志",
+		content:str
+	})
+}

+ 84 - 0
libs/login.js

@@ -0,0 +1,84 @@
+import store from "../store";
+import Cache from '../utils/cache';
+// #ifdef H5 || APP-PLUS
+import {
+	isWeixin
+} from "../utils";
+import auth from './wechat';
+// #endif
+
+import {
+	LOGIN_STATUS,
+	USER_INFO,
+	EXPIRES_TIME,
+	STATE_R_KEY
+} from './../config/cache';
+
+function prePage() {
+	let pages = getCurrentPages();
+	let prePage = pages[pages.length - 2];
+	// #ifdef H5
+	return prePage;
+	// #endif
+	return prePage.$vm;
+}
+
+export function toLogin(push, pathLogin) {
+	// store.commit("LOGOUT");
+	let path = prePage();
+	if (path) {
+		path = path.router;
+		if (path == undefined) {
+			path = location.pathname;
+		}
+	}
+	// #ifdef H5
+	else {
+		path = location.pathname;
+	}
+	// #endif
+
+	if (!pathLogin)
+		pathLogin = '/page/users/login/index'
+	Cache.set('login_back_url', path);
+	// #ifdef H5 || APP-PLUS
+	if (isWeixin()) {
+		auth.oAuth();
+	} else {
+		if (path !== pathLogin) {
+			push ? uni.navigateTo({
+				url: '/pages/users/login/index'
+			}) : uni.reLaunch({
+				url: '/pages/users/login/index'
+			});
+		}
+	}
+	// #endif
+
+	// #ifdef MP 
+
+
+	// #endif
+}
+
+
+export function checkLogin() {
+	let token = Cache.get(LOGIN_STATUS);
+	let expiresTime = Cache.get(EXPIRES_TIME);
+	let newTime = Math.round(new Date() / 1000);
+	if (expiresTime < newTime || !token) {
+		Cache.clear(LOGIN_STATUS);
+		Cache.clear(EXPIRES_TIME);
+		Cache.clear(USER_INFO);
+		Cache.clear(STATE_R_KEY);
+		return false;
+	} else {
+		store.commit('UPDATE_LOGIN', token);
+		let userInfo = Cache.get(USER_INFO, true);
+		if (userInfo) {
+			store.commit('UPDATE_USERINFO', userInfo);
+		}
+		return true;
+	}
+
+}

+ 253 - 0
libs/wechat.js

@@ -0,0 +1,253 @@
+// #ifdef H5
+import WechatJSSDK from "@/plugin/jweixin-module/index.js";
+// #endif
+
+import {
+	wechatConfig,
+	wechatAuth
+} from "@/api/wx.js";
+import {
+	WX_AUTH,
+	STATE_KEY,
+	LOGINTYPE,
+	BACK_URL
+} from '@/config/cache';
+import {
+	parseQuery
+} from '@/utils';
+import store from '@/store';
+import Cache from '@/utils/cache';
+
+class AuthWechat {
+	// #ifdef H5
+	constructor() {
+		//微信实例化对象
+		this.instance = WechatJSSDK;
+		//是否实例化
+		this.status = false;
+
+		this.initConfig = {};
+
+	}
+	// #endif
+	
+	isAndroid(){
+		let u = navigator.userAgent;
+		return u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
+	}
+
+	/**
+	 * 初始化wechat(分享配置)
+	 */
+	wechat() {
+		return new Promise((resolve, reject) => {
+			// if (this.status && !this.isAndroid()) return resolve(this.instance);
+			wechatConfig()
+				.then(res => {
+					this.instance.config(res.data);
+					this.initConfig = res.data;
+					this.status = true;
+					this.instance.ready(() => {
+						resolve(this.instance);
+					})
+				}).catch(err => {
+					console.log(err);
+					this.status = false;
+					reject(err);
+				});
+		});
+	}
+
+	/**
+	 * 验证是否初始化
+	 */
+	verifyInstance() {
+		let that = this;
+		return new Promise((resolve, reject) => {
+			if (that.instance === null && !that.status) {
+				that.wechat().then(res => {
+					resolve(that.instance);
+				}).catch(() => {
+					return reject();
+				})
+			} else {
+				return resolve(that.instance);
+			}
+		})
+	}
+	// 微信公众号的共享地址
+	openAddress() {
+		return new Promise((resolve, reject) => {
+			this.wechat().then(wx => {
+				this.toPromise(wx.openAddress).then(res => {
+					resolve(res);
+				}).catch(err => {
+					reject(err);
+				});
+			}).catch(err => {
+				reject(err);
+			})
+		});
+	}
+
+	/**
+	 * 微信支付
+	 * @param {Object} config
+	 */
+	pay(config) {
+		return new Promise((resolve, reject) => {
+			this.wechat().then((wx) => {
+				this.toPromise(wx.chooseWXPay, config).then(res => {
+					resolve(res);
+				}).catch(res => {
+					reject(res);
+				});
+			}).catch(res => {
+				reject(res);
+			});
+		});
+	}
+
+	toPromise(fn, config = {}) {
+		return new Promise((resolve, reject) => {
+			fn({
+				...config,
+				success(res) {
+					resolve(res);
+				},
+				fail(err) {
+					reject(err);
+				},
+				complete(err) {
+					reject(err);
+				},
+				cancel(err) {
+					reject(err);
+				}
+			});
+		});
+	}
+
+	/**
+	 * 自动去授权
+	 */
+	oAuth() {
+		if (uni.getStorageSync(WX_AUTH) && store.state.app.token) return;
+		const {
+			code
+		} = parseQuery();
+		if (!code) return this.toAuth();
+	}
+
+	clearAuthStatus() {
+
+	}
+
+	/**
+	 * 授权登陆获取token
+	 * @param {Object} code
+	 */
+	auth(code) {
+		return new Promise((resolve, reject) => {
+			let loginType = Cache.get(LOGINTYPE);
+			wechatAuth(code, parseInt(Cache.get("spread")), loginType)
+				.then(({
+					data
+				}) => {
+					let expires_time = data.expires_time.substring(0, 19);
+					expires_time = expires_time.replace(/-/g, '/');
+					expires_time = new Date(expires_time).getTime();
+					let newTime = Math.round(new Date() / 1000);
+					store.commit("LOGIN", {
+						token: data.token,
+						time: expires_time - newTime
+					});
+					Cache.set(WX_AUTH, code);
+					Cache.clear(STATE_KEY);
+					loginType && Cache.clear(LOGINTYPE);
+					resolve();
+				})
+				.catch(reject);
+		});
+	}
+
+	/**
+	 * 获取跳转授权后的地址
+	 * @param {Object} appId
+	 */
+	getAuthUrl(appId) {
+		const redirect_uri = encodeURIComponent(
+			`${location.origin}/pages/auth/index?back_url=` +
+			encodeURIComponent(
+				encodeURIComponent(
+					uni.getStorageSync(BACK_URL) ?
+					uni.getStorageSync(BACK_URL) :
+					location.pathname + location.search
+				)
+			)
+		);
+		uni.removeStorageSync(BACK_URL);
+		const state = encodeURIComponent(
+			("" + Math.random()).split(".")[1] + "authorizestate"
+		);
+		uni.setStorageSync(STATE_KEY, state);
+		return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_userinfo&state=${state}#wechat_redirect`;
+	}
+
+	/**
+	 * 跳转自动登陆
+	 */
+	toAuth() {
+		let that = this;
+		this.wechat().then(wx => {
+			location.href = this.getAuthUrl(that.initConfig.appId);
+		})
+	}
+
+	/**
+	 * 绑定事件
+	 * @param {Object} name 事件名
+	 * @param {Object} config 参数
+	 */
+	wechatEvevt(name, config) {
+		let that = this;
+		return new Promise((resolve, reject) => {
+			let configDefault = {
+				fail(res) {
+					console.log(res,11111);
+					if (that.instance) return reject({
+						is_ready: true,
+						wx: that.instance
+					});
+					that.verifyInstance().then(wx => {
+						return reject({
+							is_ready: true,
+							wx: wx
+						});
+					})
+				},
+				success(res) {
+					return resolve(res,2222);
+				}
+			};
+			Object.assign(configDefault, config);
+			that.wechat().then(wx => {
+				if (typeof name === 'object') {
+					name.forEach(item => {
+						wx[item] && wx[item](configDefault)
+					})
+				} else {
+					wx[name] && wx[name](configDefault)
+				}
+			})
+		});
+	}
+
+	isWeixin() {
+		return navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1;
+	}
+
+}
+
+export default new AuthWechat();
+

+ 46 - 0
main.js

@@ -0,0 +1,46 @@
+import Vue from 'vue'
+import store from './store'
+import App from './App'
+import i18n from './libs/i18n/index.js'
+/**
+ *  所有测试用数据均存放于根目录json.js
+ *  
+ *  css部分使用了App.vue下的全局样式和iconfont图标,有需要图标库的可以留言。
+ *  示例使用了uni.scss下的变量, 除变量外已尽量移除特有语法,可直接替换为其他预处理器使用
+ */
+const msg = (title, duration=1500, mask=false, icon='none')=>{
+	//统一提示方便全局修改
+	if(Boolean(title) === false){
+		return;
+	}
+	uni.showToast({
+		title,
+		duration,
+		mask,
+		icon
+	});
+}
+
+const prePage = ()=>{
+	// 获取当前页面
+	let pages = getCurrentPages();
+	let prePage = pages[pages.length - 2];
+	// #ifdef H5
+	return prePage;
+	// #endif
+	return prePage.$vm;
+}
+
+Vue.config.productionTip = false
+Vue.prototype.$fire = new Vue();
+Vue.prototype._i18n = i18n;
+Vue.prototype.$store = store;
+Vue.prototype.$api = {msg, prePage};
+
+App.mpType = 'app'
+
+const app = new Vue({
+    ...App,
+	i18n
+})
+app.$mount()

+ 117 - 0
manifest.json

@@ -0,0 +1,117 @@
+{
+    "name" : "互娛有獎",
+    "appid" : "__UNI__3DD0668",
+    "description" : "",
+    "versionName" : "1.0.13",
+    "versionCode" : 113,
+    "transformPx" : false,
+    "app-plus" : {
+        /* 5+App特有相关 */
+        "usingComponents" : true,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        "modules" : {},
+        /* 模块配置 */
+        "distribute" : {
+            /* 应用发布信息 */
+            "android" : {
+                /* android打包配置 */
+                "permissions" : [
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>"
+                ],
+                "abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
+            },
+            "ios" : {
+                "idfa" : false,
+                "dSYMs" : false
+            },
+            /* ios打包配置 */
+            "sdkConfigs" : {
+                "maps" : {},
+                "oauth" : {
+                    "weixin" : {
+                        "appid" : "",
+                        "appsecret" : "",
+                        "UniversalLinks" : ""
+                    }
+                },
+                "ad" : {}
+            },
+            "icons" : {
+                "android" : {
+                    "hdpi" : "unpackage/res/icons/72x72.png",
+                    "xhdpi" : "unpackage/res/icons/96x96.png",
+                    "xxhdpi" : "unpackage/res/icons/144x144.png",
+                    "xxxhdpi" : "unpackage/res/icons/192x192.png"
+                },
+                "ios" : {
+                    "appstore" : "unpackage/res/icons/1024x1024.png",
+                    "ipad" : {
+                        "app" : "unpackage/res/icons/76x76.png",
+                        "app@2x" : "unpackage/res/icons/152x152.png",
+                        "notification" : "unpackage/res/icons/20x20.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "proapp@2x" : "unpackage/res/icons/167x167.png",
+                        "settings" : "unpackage/res/icons/29x29.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "spotlight" : "unpackage/res/icons/40x40.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png"
+                    },
+                    "iphone" : {
+                        "app@2x" : "unpackage/res/icons/120x120.png",
+                        "app@3x" : "unpackage/res/icons/180x180.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "notification@3x" : "unpackage/res/icons/60x60.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "settings@3x" : "unpackage/res/icons/87x87.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png",
+                        "spotlight@3x" : "unpackage/res/icons/120x120.png"
+                    }
+                }
+            }
+        }
+    },
+    /* SDK配置 */
+    "quickapp" : {},
+    /* 快应用特有相关 */
+    "mp-weixin" : {
+        /* 小程序特有相关 */
+        "usingComponents" : true,
+        "appid" : "",
+        "setting" : {
+            "urlCheck" : true,
+            "minified" : true
+        }
+    },
+    "h5" : {
+        "title" : "互娛有獎",
+        "domain" : "",
+        "router" : {
+            "base" : "/index/",
+            "mode" : "hash"
+        },
+        "devServer" : {
+            "proxy" : {
+                "/api" : {
+                    "target" : "https://polkep.xyz"
+                }
+            }
+        },
+        "template" : "index.html"
+    }
+}

+ 20 - 0
package-lock.json

@@ -0,0 +1,20 @@
+{
+  "name": "PKR",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "@metamask/detect-provider": "^2.0.0"
+      }
+    },
+    "node_modules/@metamask/detect-provider": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@metamask/detect-provider/-/detect-provider-2.0.0.tgz",
+      "integrity": "sha512-sFpN+TX13E9fdBDh9lvQeZdJn4qYoRb/6QF2oZZK/Pn559IhCFacPMU1rMuqyXoFQF3JSJfii2l98B87QDPeCQ==",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    }
+  }
+}

+ 5 - 0
package.json

@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "@metamask/detect-provider": "^2.0.0"
+  }
+}

+ 293 - 0
pages.json

@@ -0,0 +1,293 @@
+{
+	"pages": [
+		// 首页
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTitleText": "Home",
+				"navigationStyle": "custom"
+			}
+		},
+		// 质押
+		{
+			"path": "pages/index/pledge",
+			"style": {
+				"navigationBarTitleText": "Project",
+				"navigationStyle": "custom"
+			}
+		},
+		// 互娱
+		{
+			"path": "pages/index/entertainment",
+			"style": {
+				"navigationBarTitleText": "Game",
+				"navigationBarBackgroundColor":"#000000",
+				"navigationBarTextStyle":"white"
+			}
+		},
+		// 资讯
+		{
+			"path": "pages/index/information",
+			"style": {
+				"navigationBarTitleText": "News",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/public/register",
+			"style": {
+				"navigationBarTitleText": "注册",
+				"navigationBarBackgroundColor":"#000000",
+				"navigationBarTextStyle":"white"
+			}
+		},
+		{
+			"path": "pages/public/login",
+			"style": {
+				"navigationBarTitleText": "登录",
+				"navigationBarBackgroundColor":"#000000",
+				"navigationBarTextStyle":"white"
+			}
+		},
+		{
+			"path": "pages/public/wxLogin",
+			"style": {
+				"navigationBarTitleText": "微信登录",
+				"app-plus": {
+					"titleNView": {
+						"type": "transparent"
+					}
+				}
+			}
+		},
+		{
+			"path": "pages/public/forget",
+			"style": {
+				"navigationBarTitleText": "忘记密码",
+				"app-plus": {
+					"titleNView": {
+						"type": "transparent"
+					}
+				}
+			}
+		},
+		{
+			"path": "pages/index/user",
+			"style": {
+				// #ifndef MP-WEIXIN
+				"navigationStyle": "custom",
+				// #endif
+				"navigationBarTitleText": "My"
+			}
+		},
+		{
+			"path": "pages/redirect/redirect",
+			"style": {
+				"navigationBarTitleText": "微信登录跳转页面",
+				"app-plus": {
+					"titleNView": false
+				}
+			}
+		},
+
+		{
+			"path": "pages/myPledge/myPledge",
+			"style": {
+				"navigationBarTitleText": "我的质押",
+				"enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#000000",
+				"navigationBarTextStyle": "white"
+			}
+
+		}, {
+			"path": "pages/introduce/introduce",
+			"style": {
+				"navigationBarTitleText": "玩法介绍",
+				"enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#000000",
+				"navigationBarTextStyle": "white"
+			}
+
+		}, {
+			"path": "pages/introduce/promotion",
+			"style": {
+				"navigationBarTitleText": "推广计划",
+				"enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#000000",
+				"navigationBarTextStyle": "white"
+			}
+
+		},
+		{
+			"path": "pages/introduce/game",
+			"style": {
+				"navigationBarTitleText": "游戏举例",
+				"enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#000000",
+				"navigationBarTextStyle": "white"
+			}
+		},
+		{
+			"path": "pages/introduce/pkedetail",
+			"style": {
+				"navigationBarTitleText": "PKR介绍",
+				"enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#000000",
+				"navigationBarTextStyle": "white"
+			}
+		},
+		
+		
+		
+		{
+			"path": "pages/myPledge/zyXingqing",
+			"style": {
+				"navigationBarTitleText": "",
+				"enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#000000",
+				"navigationBarTextStyle": "white"
+			}
+
+		}, {
+			"path": "pages/game/history",
+			"style": {
+				"navigationBarTitleText": "历史列表",
+				"enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#000000",
+				"navigationBarTextStyle": "white"
+			}
+		}
+
+	],
+	"subPackages": [{ // 模块分包
+		"root": "pages/user",
+		"name": "shop",
+		"pages": [{
+				"path": "money/recharge",
+				"style": {
+					"navigationBarTitleText": "充值",
+					"enablePullDownRefresh": false,
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+			},
+			{
+				"path": "money/withdrawal",
+				"style": {
+					"navigationBarTitleText": "奖励提现",
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+			},
+			{
+				"path": "money/team",
+				"style": {
+					"navigationBarTitleText": "錢包",
+					"navigationStyle": "custom"
+				}
+			},
+			{
+				"path": "set/set",
+				"style": {
+					"navigationBarTitleText": "设置",
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+			}, {
+				"path": "set/transaction",
+				"style": {
+					"navigationBarTitleText": "交易密码",
+					"enablePullDownRefresh": false,
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+
+			},
+			{
+				"path": "set/password",
+				"style": {
+					"navigationBarTitleText": "修改密码",
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+			},
+			{
+				"path": "set/userinfo",
+				"style": {
+					"navigationBarTitleText": "修改资料",
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+			},
+			{
+				"path": "vip/tabulation",
+				"style": {
+					"navigationBarTitleText": "会员列表",
+					"enablePullDownRefresh": false,
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+			},
+			{
+				"path": "vip/details",
+				"style": {
+					"navigationBarTitleText": "他的粉絲",
+					"enablePullDownRefresh": false,
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+			},
+			{
+				"path": "shareQrCode",
+				"style": {
+					"navigationBarTitleText": "互娛記錄",
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+			},
+			{
+				"path": "favorites",
+				"style": {
+					"navigationBarTitleText": "推廣海報",
+					"navigationBarBackgroundColor": "#000000",
+					"navigationBarTextStyle": "white"
+				}
+			}
+		]
+	}],
+	"tabBar": {
+		"color": "#C0C4CC",
+		"selectedColor": "#FEB041 ",
+		"borderStyle": "black",
+		"backgroundColor": "#000000",
+		"list": [{
+				"visible": false,
+				"pagePath": "pages/index/index",
+				"iconPath": "static/tabBar/shouye.png",
+				"selectedIconPath": "static/tabBar/shouye-home.png",
+				"text": "首頁"
+			},
+			{
+				"visible": false,
+				"pagePath": "pages/index/pledge",
+				"iconPath": "static/tabBar/baoya.png",
+				"selectedIconPath": "static/tabBar/baoya-home.png",
+				"text": "質押"
+			},
+			{
+				"visible": false,
+				"pagePath": "pages/index/information",
+				"iconPath": "static/tabBar/zixun.png",
+				"selectedIconPath": "static/tabBar/zixun-home.png",
+				"text": "資訊"
+			},
+			{
+				"visible": false,
+				"pagePath": "pages/index/user",
+				"iconPath": "static/tabBar/my.png",
+				"selectedIconPath": "static/tabBar/my-home.png",
+				"text": "我的"
+			}
+		]
+	}
+}

+ 126 - 0
pages/game/history.vue

@@ -0,0 +1,126 @@
+<template>
+	<view class="all padding-v-30 padding-c-30">
+		<view class="list padding-v-10 flex" v-for="(item,ind) in list" :key="ind">
+			<view class="le">
+				<view class="qs padding-b-10">{{$t('set.a7')}}{{item.no}}{{$t('set.a8')}}</view>
+				<view class="dy padding-b-10" v-if="item.result_info">{{item.result_info.c}}</view>
+				<view class="dy padding-b-10" v-else>{{ $t("enter.a2") }}</view>
+			</view>
+			<view class="ri flex" v-if="item.result">
+				<template v-for="it in item.arr " v-if="it.value==1">
+					<view class="sx green" v-if="it.type==1">{{ $t("enter.u6") }}</view>
+					<view class="sx green" v-if="it.type==3">{{ $t("enter.u5") }}</view>
+					<view class="sx " v-if="it.type==2">{{ $t("enter.u4") }}</view>
+					<view class="sx" v-if="it.type==4">{{ $t("enter.u7") }}</view>
+				</template>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		getGame
+	} from "@/api/game.js";
+	import empty from '@/components/empty';
+	export default {
+		components: {
+			empty
+		},
+		data() {
+			return {
+				id: '',
+				page: 1,
+				limit: 20,
+				loadingType: 'more',
+				loaded: false,
+				list: []
+			}
+		},
+		onLoad(option) {
+			this.id = option.id;
+			this.gameBetList()
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.a2"),
+			});
+		},
+		onReachBottom() {
+			this.gameBetList()
+		},
+		methods: {
+			gameBetList() {
+				let that = this
+				if (that.loadingType == 'loading' || that.loadingType == 'noMore') {
+					return
+				}
+				getGame({
+					page: that.page,
+					limit: that.limit,
+				},that.id).then(({data}) => {
+					let list = data.list.map((res)=>{
+						if(res.result_info){
+							res.result_info.c = (Number(res.result_info.c).toFixed(data.game.decimal))
+						}
+						if(res.result){
+							
+							let arr = [];
+							const ar  =res.result.split(",")
+							console.log(ar,'ar');
+							for (let i = 0; i < ar.length; i++) {
+								const s = ar[i].split(':');
+								arr.push({
+									type:s[0],
+									value:s[1]
+								})
+							}
+							res.arr = arr;
+						}
+						return res
+					})
+					that.list = that.list.concat(list)
+					that.page++
+					console.log('11111111', that.list);
+					if (list.length == that.limit) {
+						that.loadingType = 'more'
+					} else {
+						that.loadingType = 'noMore'
+					}
+					that.loaded = true
+				})
+			}
+		},
+	};
+</script>
+
+<style lang="scss">
+
+	.list {
+		line-height: 1;
+		border-bottom: 1px solid $border-color-light;
+		.le {
+			font-weight: bold;
+			.qs {
+				font-size: 20rpx;
+				color: #ffffff;
+			}
+
+			.dy {
+				font-size: 46rpx;
+				color: #fdb242;
+			}
+
+		}
+		.ri {
+			.sx {
+				padding-left: 10rpx;
+				font-size: 30rpx;
+				font-weight: bold;
+				color: #df5660;
+				&.green{
+					color: $color-green;
+				}
+			}
+		}
+	}
+	
+</style>

+ 759 - 0
pages/index/entertainment.vue

@@ -0,0 +1,759 @@
+<template>
+	<view class="all">
+		<view class="padding-t-30"></view>
+		<view class="top-content">
+			<view class="top-one flex">
+				<view class="action-title">
+					<text v-if="history.next">{{$t('indexenter.第')}}{{history.next.no}}{{$t('indexenter.期')}}</text>
+					<text v-else>loading...</text>
+				</view>
+				<view class="end-time">
+					<text>{{$t('indexenter.距离结束')}}</text>
+					<text class="time">
+						<text v-if="time.H<10">0</text>
+						{{time.H}}:
+						<text v-if="time.M<10">0</text>
+						{{time.M}}:
+						<text v-if="time.S<10">0</text>
+						{{time.S}}
+					</text>
+				</view>
+			</view>
+			<view class="top-two flex" v-if="history.list.length>0">
+				<view class="old-title flex-start">
+					<text>{{$t('indexenter.第')}}{{history.list[0].no}}{{$t('indexenter.期')}}</text>
+					<image v-for="ls in history.list[0].result_info" class="dice"
+						:src="`../../static/img/dice${ls}.png`" mode="scaleToFill"></image>
+				</view>
+				<view class="old-num">
+					<!-- {{$t('indexenter.竞猜数')}}:10 -->
+					{{$t('indexenter.结果')}}:
+					<text class="margin-l-10"
+						v-for="ll in history.list[0].typelist">{{$t(`indexenter.${ll.type}`)}}</text>
+				</view>
+			</view>
+		</view>
+
+		<view class="number flex">
+			<view class="item-num" :class="{action:ind==actiontype}" v-for="(item,ind) in history.base.include_function"
+				@click="actiontype=ind">
+				<view class="type">
+					{{$t(`indexenter.${item.name}`)}}
+				</view>
+				<view class="percentage">
+					{{item.bfb}}%
+				</view>
+			</view>
+		</view>
+		<view class="money-list flex">
+			<view class="list-ls flex" @click="upOnBtnData.value=item.value" v-for="(item,ind) in moneyList">
+				<view class="image">
+					<image class="img" :src="item.url" mode="widthFix"></image>
+				</view>
+				<view class="list">
+					{{item.value}}
+				</view>
+			</view>
+		</view>
+		<view class="pay-title padding-l-30">
+			{{$t('indexenter.竞猜总额')}}(USDT):
+		</view>
+		<view class="pay-money-box flex padding-c-30 padding-v-10">
+			<input class="pay-money" type="number" v-model="upOnBtnData.value" />
+			<view class="buttom-del" @click="upOnBtnData.value=0">
+				{{$t('indexenter.清空')}}
+			</view>
+		</view>
+		<view class="pay-title padding-c-30 flex padding-v-20">
+			<view>
+				{{$t('indexenter.竞猜总额')}}:
+			</view>
+			<view class="font-color-yellow">
+				0
+				USDT
+			</view>
+		</view>
+		<view class="push-buttom" @click="onPayBet">
+			{{$t('indexenter.确认')}}
+		</view>
+
+		<view class="chz flex" @click="nav('/pages/user/money/recharge')">
+			<view>
+				<view class="yue padding-b-10">{{$t('enter.u15')}}</view>
+				<view class="yes">{{userWallet}}USDT</view>
+			</view>
+			<view class="flex-start">
+				<view class="quc">{{$t('enter.u16')}}</view>
+				<image class="choz" src="../../static/img/img39.png" mode="scaleToFill"></image>
+			</view>
+		</view>
+
+		<view class="history-title padding-l-30 margin-t-30 flex-start">
+			<view :class="{action:historyType==0}" @click="historyType=0">
+				{{$t('indexenter.押注记录')}}
+			</view>
+			<view class="margin-l-30" :class="{action:historyType==1}" @click="historyType=1">
+				{{$t('indexenter.近期记录')}}
+			</view>
+		</view>
+
+		<view class="history-list">
+			<view class="history-title-type flex">
+				<view class="history-item">
+					{{$t('indexenter.期号')}}
+				</view>
+				<view class="history-item" v-if="historyType==0">
+					{{$t('indexenter.竞猜值')}}
+				</view>
+				<view class="history-item">
+					{{$t('indexenter.竞猜数')}}
+				</view>
+				<view class="history-item">
+					{{$t('indexenter.结果')}}
+				</view>
+			</view>
+			<view class="history-title-type flex margin-t-30" v-for="(item,ind) in betList.list" :key="ind"
+				v-if="historyType==0">
+				<view class="history-item font-color-yellow"
+					:class="{'font-color-gray':item.result==0,'font-color-red':item.result==1}">
+					{{item.room.no}}
+				</view>
+				<view class="history-item font-color-red">
+					<text class="margin-l-10" v-for="(ll,ind) in history.base.include_function"
+						v-if="item.bet==ll.id">{{$t(`indexenter.${ll.name}`)}}</text>
+				</view>
+				<view class="history-item font-color-red">
+					{{item.room.result_info||$t('enter.a2')}}
+				</view>
+				<view class="history-item font-color-yellow" v-if="item.typelist.length>0">
+					<text class="margin-l-10" v-for="ll in item.typelist">{{$t(`indexenter.${ll.type}`)}}</text>
+				</view>
+				<view class="history-item font-color-yellow" v-else>
+					{{$t('enter.a2')}}
+				</view>
+			</view>
+			<view class="history-title-type flex margin-t-30" v-for="(item,ind) in history.list" :key="ind"
+				v-if="historyType==1">
+				<view class="history-item font-color-yellow"
+					:class="{'font-color-gray':item.result==0,'font-color-red':item.result==1}">
+					{{item.no}}
+				</view>
+				<!-- <view class="history-item font-color-red">
+					<text class="margin-l-10"
+						 v-for="(ll,ind) in history.base.include_function" v-if="item.bet==ll.id">{{$t(`indexenter.${ll.name}`)}}</text>
+				</view> -->
+				<view class="history-item font-color-red flex">
+					<image v-for="ls in item.result_info" class="dice-number" :src="`../../static/img/dice${ls}.png`"
+						mode="scaleToFill"></image>
+				</view>
+				<view class="history-item font-color-yellow" v-if="item.typelist.length>0">
+					<text class="margin-l-10" v-for="ll in item.typelist">{{$t(`indexenter.${ll.type}`)}}</text>
+				</view>
+				<view class="history-item font-color-yellow" v-else>
+					{{$t('enter.a2')}}
+				</view>
+			</view>
+		</view>
+
+
+		<uni-popup type="bottom" ref="popup" :mask-click="false" @maskClick='colsePayPassword'>
+			<inputPassword @commit='KeyInfo' @colse='colsePayPassword'></inputPassword>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import {} from "@/api/game.js";
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex';
+	import {
+		getGame,
+		getGameList,
+		gameWallet,
+		gameBetList,
+		gameBetIn,
+		// gameTest
+	} from "@/api/game.js";
+	import {
+		saveUrl,
+		interceptor
+	} from '@/utils/loginUtils.js';
+	import {
+		getTime
+	} from '@/utils/rocessor.js';
+	import inputPassword from "@/components/input-password/input-password.vue";
+	export default {
+		components: {
+			inputPassword
+		},
+		computed: {
+			...mapState("user", ["hasLogin"]),
+		},
+		data() {
+			return {
+				historyType: 0, //记录类型
+				// 当前选中的大小奇偶
+				actiontype: 0,
+				id: '',
+				moneyList: [{
+						url: '/static/img/money_pay_1.png',
+						value: 5
+					}, {
+						url: '/static/img/money_pay_2.png',
+						value: 10
+					},
+					{
+						url: '/static/img/money_pay_3.png',
+						value: 30
+					},
+					{
+						url: '/static/img/money_pay_4.png',
+						value: 50
+					}
+				],
+				// 游戏信息
+				time: {
+					H: 0,
+					M: 0,
+					S: 0,
+					// 保存倒计时对象
+					t: ''
+				},
+				// 游戏信息
+				history: {
+					list: [], //游戏进行记录
+					page: 1,
+					limit: 10,
+					// 基础数据
+					base: {},
+					next: "",
+					now: {}
+				},
+				// 游戏押注记录
+				betList: {
+					list: [], //游戏进行记录
+					page: 1,
+					limit: 5,
+				},
+				userWallet: 0,
+				upOnBtnData: {
+					type: '',
+					// 当前输入的密码
+					passwordArr: '',
+					value: 0,
+				},
+				// 保存获取下次游戏对象
+				getNextTimeObj: '',
+				loadPage:true,
+			};
+		},
+		onLoad(option) {
+			this.id = option.id;
+			uni.setNavigationBarTitle({
+				title: option.title
+			});
+		},
+		onShow() {
+			if (!this.hasLogin) {
+				uni.showModal({
+					title: this.$t('enter.c4'),
+					content: this.$t('enter.b5'),
+					cancelText: this.$t('indexenter.取消'),
+					confirmText: this.$t('indexenter.确定'),
+					success: (e) => {
+						// 判断是否点击确认按钮
+						if (e.confirm) {
+							// 保存当前页面地址
+							saveUrl()
+							// 跳转页面
+							interceptor()
+						}
+					}
+				})
+				return
+			}
+			this.getUserWallet();
+			this.gameInit(this.id);
+		},
+		// 关闭循环
+		onHide() {
+			const that = this;
+			// 倒计时清理
+			that.initData();
+		},
+		onUnload() {
+			const that = this;
+			that.initData();
+		},
+		methods: {
+			getTime,
+			// 初始化
+			gameInit(id) {
+				console.log('id', id);
+				// await gameTest();
+				// 获取基础信息
+				this.getGame(id);
+			},
+			// 获取游戏信息
+			getGame(id) {
+				const that = this;
+				getGame({
+					page: that.history.page,
+					limit: that.history.limit
+				}, id).then(({
+					data
+				}) => {
+					that.history.base = data.game || {};
+					that.history.base.include_function = that.history.base.include_function.map((res) => {
+						res.bfb = res.ratio * 1 * that.history.base.success_ratio / 100;
+						return res
+					})
+					that.history.next = data.now_game || '';
+					that.history.now = data.now_game || '';
+
+					if (data.list) {
+						that.history.list = data.list.map((res) => {
+							res.result_info = res.result_info.split(",");
+							res.typelist = that.resultLottery(res.result);
+							return res
+						});
+						console.log(that.history.list, 'that.history.list');
+					} else {
+						that.history.list = [];
+					}
+					// 判断是否不存在游戏,并且没有倒计时对象,且在当前页面
+					if (that.loadPage && !that.history.next) {
+						that.getNextTimeObj = setTimeout(() => {
+							that.getGame(id)
+						}, 1000)
+						return
+					}
+					if (that.history.next && that.getNextTimeObj) {
+						clearTimeout(that.getNextTimeObj);
+						// 清空倒计时对象
+						that.getNextTimeObj = '';
+					}
+					// 判断是否有活动并且正在进行中
+					if (that.history.next && !that.getNextTimeObj) {
+						that.opTiem();
+						that.gameBetList()
+					}
+				})
+			},
+			// 处理中奖信息数据
+			resultLottery(st) {
+				const that = this;
+				let typelist = [];
+				if (st) {
+					st.split(",").forEach((r) => {
+						const ar = r.split(':');
+						if (ar[1] == '1') {
+							for (let i = 0; i < that.history.base.include_function.length; i++) {
+								if (that.history.base.include_function[i].id == ar[0] * 1) {
+									typelist.push({
+										type: that.history.base.include_function[i].name
+									})
+									break
+								}
+							}
+						}
+					});
+				}
+				return typelist
+			},
+			// 游戏押注记录
+			gameBetList() {
+				const that = this;
+				if (that.historyType == 0) {
+					const lineNum = that.history.base.decimal;
+					gameBetList({
+						page: 1,
+						limit: 10,
+						id: that.history.base.id,
+					}).then(({
+						data
+					}) => {
+						that.betList.list = data.bet_log.map((res) => {
+							res.typelist = that.resultLottery(res.room.result);
+							return res
+						});
+					})
+				}
+
+			},
+			// 开始倒计时
+			async opTiem() {
+				const that = this;
+				try {
+					// 判斷是否有游戲信息并且有正在進行中游戏
+					if (that.history.base.id && that.history.next) {
+						// console.log(that.history.base.id, that.history.next,
+						// 	'that.history.base.id && that.history.next');
+						that.time.t = setInterval(() => {
+							that.getOutTime();
+						}, 1000)
+					}
+				} catch (e) {
+					console.log(e, '定时');
+				}
+			},
+			// 清除加载
+			initData() {
+				const that = this;
+				that.loadPage = false;
+				// 关闭倒计时
+				clearTimeout(that.getNextTimeObj);
+				clearInterval(that.time.t);
+				// 清空倒计时对象
+				that.getNextTimeObj = '';
+				that.time = {
+					H: 0,
+					M: 0,
+					S: 0,
+					t: ''
+				};
+			},
+			// 点击触发支付事件
+			onPayBet() {
+				if (!this.upOnBtnData.value) {
+					uni.showToast({
+						title: this.$t('enter.a9'),
+						icon: "error"
+					})
+					return
+				}
+				if (!this.history.next) {
+					uni.showModal({
+						title: this.$t('enter.c4'),
+						content: this.$t('enter.a3'),
+						showCancel: false,
+						confirmText: this.$t('indexenter.确定'),
+					});
+					return
+				}
+				this.upOnBtnData.type = this.history.base.include_function[this.actiontype].id;
+				this.openPayPassword();
+			},
+			// 打开支付弹窗
+			openPayPassword() {
+				this.upOnBtnData.show = true;
+				this.$refs.popup.open();
+			},
+			// 关闭支付弹窗
+			colsePayPassword() {
+				this.upOnBtnData.show = false;
+				this.$refs.popup.close();
+			},
+			// 密码输入完成后调用下注
+			KeyInfo(val) {
+				const that = this;
+				that.upOnBtnData.passwordArr = val;
+				const name = that.$t(`indexenter.${that.history.base.include_function[that.actiontype].name}`)
+				that.colsePayPassword();
+				uni.showModal({
+					title: that.$t('enter.c4'),
+					content: `${that.$t('enter.a8')}${that.upOnBtnData.value}USDT${that.$t('enter.a10')}${that.history.next.no}${name}`,
+					cancelText: that.$t('indexenter.取消'),
+					confirmText: that.$t('indexenter.确定'),
+					success: res => {
+						if (res.confirm) {
+							that.gameBetIn();
+						}
+					},
+				});
+			},
+			// 参与压住
+			gameBetIn(type) {
+				const that = this;
+				const upData = {
+					id: that.history.next.id,
+					bet: that.upOnBtnData.type,
+					num: that.upOnBtnData.value,
+					trade_password: that.upOnBtnData.passwordArr
+				};
+				uni.showLoading({
+					mask: true
+				})
+				that.upOnBtnData.value = '';
+				gameBetIn(upData).then((res) => {
+					uni.hideLoading()
+					uni.showToast({
+						title: res.msg
+					});
+					that.gameBetList();
+					that.getUserWallet();
+				}).catch((res) => {
+					uni.hideLoading();
+					uni.showToast({
+						title: res.msg
+					});
+				})
+			},
+			// 获取用户余额信息
+			getUserWallet() {
+				gameWallet().then((res) => {
+					const balance = Number(res.data.back.USDT.money.money);
+					this.userWallet = balance.toFixed(2);
+					// this.userWallet = +res.data.back.USDT.money.money
+				})
+			},
+			// 获取倒计时时间
+			getOutTime() {
+				const that = this;
+				const da = (new Date()).getTime();
+				const timenum = that.history.next.close_time * 1000 - da;
+				// console.log(timenum, that.history.next.open_time, da, '计算');
+				if (timenum > 0) {
+					that.time.H = Math.floor(timenum / 1000 / 60 / 60);
+					that.time.S = Math.floor(timenum / 1000 % 60)
+					that.time.M = Math.floor(timenum / 1000 / 60 % 60);
+				}
+				if (that.time.H == 0 && that.time.M == 0 && that.time.S == 0) {
+					console.log('归0');
+					clearInterval(that.time.t);
+					// 延时调用防止数据重复加载
+					setTimeout(() => {
+						that.getGame(that.history.base.id);
+					}, 2000)
+				}
+
+			},
+			// 页面跳转
+			nav(url) {
+				console.log('tz');
+				if (!this.hasLogin) {
+					uni.showModal({
+						title: this.$t('enter.c4'),
+						content: this.$t('enter.b5'),
+						cancelText: this.$t('indexenter.取消'),
+						confirmText: this.$t('indexenter.确定'),
+						success: (e) => {
+							// 判断是否点击确认按钮
+							if (e.confirm) {
+								// 保存当前页面地址
+								saveUrl()
+								// 跳转页面
+								interceptor()
+							}
+						}
+					})
+					return
+				}
+				uni.navigateTo({
+					url,
+					fail(err) {
+						console.log(err);
+					}
+				});
+			},
+		},
+	};
+</script>
+
+<style lang="scss">
+	$yellow: #FDAF41;
+
+	.all {
+		width: 750rpx;
+		/* height: 2500rpx; */
+		height: 100%;
+		padding-top: var(--status-bar-height);
+		padding-bottom: 30rpx;
+		color: #FFFFFF;
+	}
+
+	.chz {
+		background: #191a1f;
+		border-radius: 20rpx;
+		margin: 0 30rpx;
+		color: #ffffff;
+		font-weight: bold;
+		padding: 20rpx 30rpx;
+
+		.yue {
+			font-size: 28rpx;
+		}
+
+		.yes {
+			color: $color-yellow;
+		}
+
+		.quc {
+			font-size: 26rpx;
+			font-weight: 500;
+		}
+
+		.choz {
+			width: 22rpx;
+			height: 14rpx;
+		}
+	}
+
+	.number {
+		flex-wrap: wrap;
+		padding: 70rpx;
+		padding-bottom: 0;
+
+		.item-num {
+			line-height: 1;
+			text-align: center;
+			font-weight: bold;
+			width: 260rpx;
+			border-radius: 20rpx;
+			margin-bottom: 70rpx;
+			padding: 30rpx;
+			background: linear-gradient(-74deg, rgba(206, 156, 109, 0.4), rgba(255, 236, 214, 0.4));
+
+			&.action {
+				background: linear-gradient(-74deg, #CE9C6D, #FFECD6);
+			}
+
+			.type {
+				font-size: 72rpx;
+			}
+
+			.percentage {
+				padding-top: 20rpx;
+				font-size: $font-base;
+			}
+		}
+	}
+
+	.money-list {
+		padding: 0 30rpx;
+		color: #FFF;
+		text-align: center;
+		align-items: stretch;
+		padding-bottom: 50rpx;
+
+		.list-ls {
+			width: 23%;
+			flex-direction: column;
+			align-items: stretch;
+			font-size: 35rpx;
+			font-weight: bold;
+
+			.image {
+				.img {
+					width: 100%;
+				}
+			}
+		}
+	}
+
+	.pay-title {
+		font-size: 26rpx;
+	}
+
+	.pay-money-box {
+		.pay-money {
+			flex-grow: 1;
+			font-size: 38rpx;
+			font-weight: bold;
+			color: $yellow;
+		}
+
+		.buttom-del {
+			background-color: $yellow;
+			border-radius: 6rpx;
+			color: #000000;
+			font-size: 26rpx;
+			padding: 14rpx 26rpx;
+			line-height: 1;
+		}
+	}
+
+	.push-buttom {
+		text-align: center;
+		line-height: 1;
+		color: #000000;
+		background-color: $yellow;
+		padding: 30rpx;
+		margin: 30rpx;
+		border-radius: 10rpx;
+		margin-bottom: 40rpx;
+	}
+
+	.history-title {
+		font-size: $font-lg;
+
+		.action {
+			color: $yellow;
+		}
+	}
+
+	.history-list {
+		line-height: 1;
+		background-color: #1E1E1F;
+		border-radius: 10rpx;
+		padding: 30rpx;
+		margin: 30rpx;
+
+		.history-title-type {
+			font-size: 24rpx;
+
+			.history-item {
+				text-align: center;
+				width: 25%;
+
+				.dice-number {
+					width: 40rpx;
+					height: 40rpx;
+				}
+
+				&:nth-child(1) {
+					text-align: left;
+					width: 30%;
+				}
+
+				&:nth-child(2) {
+					width: 30%;
+				}
+
+				&:nth-child(3) {
+					width: 20%;
+				}
+
+				&:nth-child(4) {
+					text-align: right;
+					width: 20%;
+				}
+			}
+		}
+	}
+
+	.top-content {
+		padding: 30rpx;
+		color: #FFF;
+		background-color: #1E1E1F;
+		line-height: 1;
+
+		.top-one {
+			font-size: $font-lg;
+
+			.time {
+				padding-left: 10rpx;
+				color: $color-red;
+			}
+		}
+
+		.top-two {
+			font-size: 26rpx;
+			padding-top: 20rpx;
+
+			.old-title {
+				.dice {
+					width: 54rpx;
+					height: 54rpx;
+					margin-left: 10rpx;
+				}
+			}
+
+			.old-num {
+				color: $color-yellow;
+			}
+		}
+	}
+</style>

+ 306 - 0
pages/index/index.vue

@@ -0,0 +1,306 @@
+<template>
+	<view class="container">
+		<view class="top flex">
+			<view class="icon1 flex">
+				<image class="img margin-r-10" src="../../static/shouye/shouye1.png" mode="scaleToFill"></image>
+				<text class="tet">{{$t('login.a0')}}</text>
+			</view>
+			<view class="flex">
+				<view class="icon2 text clamp margin-r-10">
+					{{userInfo.account||'链接钱包'}}
+				</view>
+				<view class="icon1  margin-r-10">
+					<image class="langTip" src="../../static/shouye/shouye2.png" mode="scaleToFill"></image>
+				</view>
+				<view class="text1  margin-r-10">
+					<picker :range="langList" range-key='label' @change="selectLang">
+						<view>{{label}}</view>
+					</picker>
+				</view>
+				<view class="icon1">
+					<image class="langTipDom" src="../../static/shouye/shouye3.png" mode="scaleToFill"></image>
+				</view>
+			</view>
+		</view>
+		<view class="flex item">
+			<view class="item-style flex" v-for="(item,ind) in gameList"
+				@click="openurl(`/pages/index/entertainment?title=${item.name}&id=${item.id}`)">
+				<image class="item-tip" :src="`../../static/shouye/index_item_${ind+1}.png`" mode="scaleToFill">
+				</image>
+				<view class="name">
+					{{item.name}}
+				</view>
+				<view class="item-next flex-center">
+					<image src="../../static/img/zhiya1.png" mode="widthFix" class="next-img"></image>
+				</view>
+			</view>
+		</view>
+		<view class="flex shop-detail-data">
+			<view class="data-list">
+				<view class="num-box">
+					<text>{{active_user}}</text><text class="num-tip">+</text>
+				</view>
+				<view class="name">
+					{{$t('homepledge.活跃用户')}}
+				</view>
+			</view>
+			<view class="data-list">
+				<view class="num-box">
+					<text>1000000</text><text class="num-tip">+</text>
+				</view>
+				<view class="name">
+					{{$t('homepledge.累计返奖')}}
+				</view>
+			</view>
+			<view class="data-list">
+				<view class="num-box">
+					<text>10000</text><text class="num-tip">+</text>
+				</view>
+				<view class="name">
+					{{$t('homepledge.总用户')}}
+				</view>
+			</view>
+		</view>
+
+		<view class="title">
+			{{$t('homepledge.游戏流程')}}
+		</view>
+		<image class="conetnt-img" src="../../static/shouye/index-content.png" mode="widthFix"></image>
+		<view class="title">
+			{{$t('homepledge.合作伙伴')}}
+		</view>
+		<image class="conetnt-img" src="../../static/shouye/index-bottom.png" mode="widthFix"></image>
+		<taber tab='index'></taber>
+	</view>
+</template>
+<script>
+	import {
+		getIndex
+	} from '@/api/index.js';
+	import {
+		getGameList,
+	} from "@/api/game.js";
+	import {
+		mapState,
+		mapActions,
+		mapMutations
+	} from "vuex";
+	import taber from "@/components/footer/footer.vue";
+	export default {
+		components: {
+			taber
+		},
+		data() {
+			return {
+				gameList: [],
+				active_user: '0'
+			}
+		},
+		computed: {
+			...mapState({
+				langList: "langList",
+				lang: "lang",
+			}),
+			...mapState('user', ['userInfo']),
+			label() {
+				const label = this.langList.find((item) => {
+					console.log(this.lang, item.value);
+					return item.value == this.lang
+				}).label;
+				return label
+			}
+		},
+		onLoad(option) {
+			// #ifndef MP
+			if (option.spread) {
+				// 存储其他邀请人
+				uni.setStorageSync('spread', option.spread);
+			}
+			// #endif
+			// #ifdef MP
+			if (option.scene) {
+				// 存储小程序邀请人
+				uni.setStorage({
+					key: 'spread_code',
+					data: option.scene
+				});
+			}
+			// #endif
+		},
+		onShow() {
+			this.getGameList();
+			this.loadData();
+		},
+		methods: {
+			...mapMutations('user', ['setUserInfo', 'login']),
+			...mapActions({
+				setLang: "setLang",
+			}),
+			openurl(url){
+				uni.navigateTo({
+					url: url,
+					fail: (err) => {
+						uni.showModal({
+							title: '错误',
+							content: err,
+							showCancel: false,
+						});
+					}
+				});
+			},
+			// 请求载入数据
+			async loadData() {
+				getIndex({})
+					.then(({
+						data
+					}) => {
+						this.active_user = data.active_user
+						console.log(data);
+					})
+					.catch(e => {});
+			},
+			selectLang(value) {
+				this.setLang(this.langList[value.detail.value].value);
+			},
+
+			getGameList() {
+				getGameList().then((res) => {
+					this.gameList = res.data.list;
+
+					if (this.gameList.length > 2) {
+						this.gameList = this.gameList.slice(0, 2)
+					}
+				})
+			},
+		},
+	}
+</script>
+
+<style lang="scss">
+	.container {
+		width: 100%;
+		background-color: #000000;
+		padding-top: var(--status-bar-height);
+	}
+
+	.title {
+		color: $base-color;
+		text-align: center;
+		font-size: 58rpx;
+
+	}
+
+	.item {
+		padding: 30rpx;
+
+		.item-style {
+			border-radius: 20rpx;
+			width: 320rpx;
+			padding: 30rpx 0;
+			background-color: #191A1F;
+			flex-direction: column;
+			color: #FFFFFF;
+			font-size: 38rpx;
+
+			.item-tip {
+				width: 209rpx;
+				height: 209rpx;
+			}
+
+			.name {
+				font-weight: bold;
+			}
+
+			.item-next {
+				margin-top: 20rpx;
+				width: 34rpx;
+				height: 34rpx;
+				border-radius: 20rpx;
+				background-color: $color-yellow;
+				font-size: 0;
+
+				.next-img {
+					width: 10rpx;
+				}
+			}
+		}
+	}
+
+	.shop-detail-data {
+		padding: 50rpx 30rpx;
+
+		.data-list {
+			text-align: center;
+
+			.num-box {
+				color: #FFF;
+				font-size: 40rpx;
+				font-weight: bold;
+
+				.num-tip {
+					font-size: $font-lg;
+					color: $color-yellow;
+				}
+			}
+
+			.name {
+				font-size: $font-sm;
+				color: $font-color-disabled;
+			}
+		}
+	}
+
+	.conetnt-img {
+		width: 690rpx;
+		margin: 30rpx;
+		margin-top: 50rpx;
+	}
+
+	.top {
+		font-weight: 500;
+		padding: 40rpx 30rpx 24rpx 30rpx;
+		line-height: 1;
+
+		.icon1 {
+			line-height: 0;
+
+			.img {
+				width: 47rpx;
+				height: 47rpx;
+			}
+
+			.tet {
+				font-size: 28rpx;
+				color: #C3A76C;
+			}
+		}
+
+		.icon2 {
+			background: #292C3D;
+			border: 2px solid #414243;
+			border-radius: 21rpx;
+		}
+
+		.langTip {
+			width: 34rpx;
+			height: 34rpx;
+		}
+
+		.langTipDom {
+			width: 23rpx;
+			height: 15rpx;
+		}
+
+		.text {
+			font-size: 24rpx;
+			color: #FFFFFF;
+			padding: 10rpx 20rpx;
+			max-width: 200rpx;
+		}
+
+		.text1 {
+			font-size: 24rpx;
+			color: #FFFFFF;
+		}
+	}
+</style>

+ 148 - 0
pages/index/information.vue

@@ -0,0 +1,148 @@
+<template>
+	<view class="content">
+		<view class="list flex" @click="nav('/pages/introduce/introduce')">
+			<image class="img" src="../../static/img/zixun1.png" mode="scaleToFill"></image>
+			<view class="text">
+				{{$t('homeinformation.m1')}}
+			</view>
+		</view>
+		<view class="list flex" @click="nav('/pages/introduce/promotion')">
+			<image class="img" src="../../static/img/zixun2.png" mode="scaleToFill"></image>
+			<view class="text">
+				{{$t('homeinformation.m0')}}
+			</view>
+		</view>
+		<view class="list flex" @click="nav('/pages/introduce/game')">
+			<image class="img" src="../../static/img/zixun3.png" mode="scaleToFill"></image>
+			<view class="text">
+				{{$t('homeinformation.m2')}}
+			</view>
+		</view>
+		<view class="list flex" @click="nav('/pages/introduce/pkedetail')">
+			<image class="img" src="../../static/img/zixun4.png" mode="scaleToFill"></image>
+			<view class="text">
+				{{$t('homepledge.PKR介绍')}}
+			</view>
+		</view>
+		<view class="tit padding-t-30 margin-t-20">
+			{{$t('homeinformation.m4')}}
+		</view>
+
+		<view class="pro flex">
+			<view class="im">
+				<image class="image" src="../../static/img/zixun7.png" mode="heightFix"></image>
+				<view class="wen flex">{{$t('homeinformation.m5')}}</view>
+			</view>
+			<view class="im">
+				<image class="image" src="../../static/img/zixun8.png" mode="heightFix"></image>
+				<view class="wen flex">{{$t('homeinformation.m6')}}</view>
+			</view>
+		</view>
+
+		<view class="infor flex">
+			<view class="im">
+				<image class="image" src="../../static/img/zixun10.png" mode="heightFix"></image>
+				<view class="wen flex">{{$t('homeinformation.m7')}}</view>
+			</view>
+			<view class="im">
+				<image class="image" src="../../static/img/zixun6.png" mode="heightFix"></image>
+				<view class="wen flex">{{$t('homeinformation.m8')}}</view>
+			</view>
+			<view class="im">
+				<image class="image" src="../../static/img/zixun9.png" mode="heightFix"></image>
+				<view class="wen flex">{{$t('homeinformation.m9')}}</view>
+			</view>
+		</view>
+		<taber tab='information'></taber>
+	</view>
+</template>
+
+<script>
+	import taber from "@/components/footer/footer.vue";
+	export default {
+		components: {
+			taber
+		},
+		data() {
+			return {};
+		},
+		methods: {
+			nav(url) {
+				uni.navigateTo({
+					url
+				})
+			},
+			navigatorH() {
+				uni.switchTab({
+					url: '/pages/index/entertainment'
+				})
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	.content {
+		width: 750rpx;
+		background-color: $page-color-base;
+		padding-top: var(--status-bar-height);
+		padding-bottom: 30rpx;
+	}
+
+	.list {
+		margin: 0 30rpx;
+		align-items: flex-start;
+		padding: 30rpx 0;
+		border-bottom: 1px solid rgba(255,255,255,0.3);
+		.img {
+			width: 200rpx;
+			height: 160rpx;
+		}
+
+		.text {
+			padding: 10rpx 0;
+			padding-left: 20rpx;
+			
+			font-size: 30rpx;
+			font-weight: bold;
+			color: #FFFFFF;
+			flex-grow: 1;
+		}
+	}
+
+	.infor {
+		margin-top: 30rpx;
+		justify-content: space-around;
+		padding: 0 20rpx;
+	}
+	.pro {
+		padding: 0 155rpx;
+		padding-top: 50rpx;
+		
+	}
+	.im {
+		width: 200rpx;
+		background-color: #191a1f;
+		text-align: center;
+		padding: 0 10rpx;
+		padding-top: 30rpx;
+		font-weight: bold;
+		border-radius: 20rpx;
+		.image {
+			height: 100rpx;
+		}
+		.wen {
+			justify-content: center;
+			height: 100rpx;
+			color: #FFFFFF;
+			font-size: 20rpx;
+			text-align: center;
+		}
+	}
+	.tit {
+		text-align: center;
+		font-size: 49rpx;
+		font-weight: 500;
+		color: #FFFFFF;
+	}
+</style>

+ 64 - 0
pages/index/information2.vue

@@ -0,0 +1,64 @@
+<template>
+	<view class="content">
+		<image src="../../static/shouye/index_logo.png" mode="scaleToFill" class="index-logo"></image>
+		<view class="title">
+			{{$t('homepledge.PKR介绍')}}
+		</view>
+		<view class="description">
+			<rich-text :nodes="$t('homepledge.description')"></rich-text>
+		</view>
+		<taber tab='information'></taber>
+	</view>
+</template>
+
+<script>
+	import taber from "@/components/footer/footer.vue";
+	export default {
+		components: {
+			taber
+		},
+		data() {
+			return {};
+		},
+		methods: {
+			nav(url) {
+				uni.navigateTo({
+					url
+				})
+			},
+			navigatorH() {
+				uni.switchTab({
+					url: '/pages/index/entertainment'
+				})
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	.content {
+		width: 750rpx;
+		background-color: $page-color-base;
+		padding-top: var(--status-bar-height);
+		padding-bottom: 30rpx;
+	}
+
+	.title {
+		color: $base-color;
+		text-align: center;
+		font-size: 58rpx;
+	
+	}
+	.index-logo {
+		width: 297rpx;
+		height: 270rpx;
+		margin: 0 226rpx;
+	}
+	.description {
+		color: #FFFFFF;
+		font-size: $font-base;
+		padding: 30rpx;
+		line-height: 2rem;
+	
+	}
+</style>

+ 240 - 0
pages/index/pledge.vue

@@ -0,0 +1,240 @@
+<template>
+	<view class="all">
+		<view class="top">
+			<text>{{$t('homepledge.m0')}}</text>
+		</view>
+		<image class="img" src="../../static/img/zhiya2.png" mode="scaleToFill" style=""></image>
+		<view @click="nav('/pages/myPledge/myPledge')" class="my flex">
+			<view class="flex">
+				<image class="titleTip margin-r-10" src="../../static/img/zhiya3.png" mode=""></image>
+				<view>
+					{{$t('homepledge.m1')}}
+				</view>
+			</view>
+			<image class="right" src="../../static/img/zhiya1.png" style="" mode=""></image>
+		</view>
+		<view class="buttom flex" v-for="(item,ind) in list" @click="nav('/pages/myPledge/zyXingqing?id='+item.id)">
+			<view class="le" >
+				<view class="le1 title ">
+					{{item.name}}
+				</view>
+				<view class="le1 qt">
+					{{item.single_time_min*1}}U{{$t('homepledge.m2')}} | {{item.day}}{{$t('homepledge.m3')}}
+				</view>
+				<view class="le1 ze">
+					{{$t('homepledge.total')}}:{{item.stock*1}}U
+				</view>
+				<!-- <view class="le2 flex font-color-gray">
+					<view class="line margin-r-10">
+						<view class="line-action" :style="{'margin-left': -(100-item.bfb)+'%'}">
+
+						</view>
+					</view>
+					<view>{{item.bfb}}%</view>
+				</view> -->
+			</view>
+			<view class="ri">
+				<view class="r1 margin-b-20"> {{item.day_get}}% </view>
+				<view class="r2 margin-b-30 font-color-gray"> {{$t('homepledge.a4')}} </view>
+				<view class="add-buttom">
+					{{$t('homepledge.a5')}}
+				</view>
+			</view>
+		</view>
+		<taber tab='pledge'></taber>
+	</view>
+</template>
+
+<script>
+	import taber from "@/components/footer/footer.vue";
+	import {
+		lock
+	} from "@/api/mypledge.js"
+	import {
+		saveUrl,
+		interceptor
+	} from '@/utils/loginUtils.js';
+	import {
+		mapState
+	} from 'vuex';
+	export default {
+		components: {
+			taber
+		},
+		computed: {
+			...mapState('user', ['hasLogin'])
+		},
+		data() {
+			return {
+				page: 1,
+				limit: 10,
+				loadingType: 'more',
+				loaded: false,
+				list: []
+			}
+		},
+		onLoad() {
+			this.loadData()
+		},
+		onReachBottom() {
+			this.loadData()
+		},
+		methods: {
+			navigator() {
+				uni.navigateTo({
+					url: '/pages/myPledge/myPledge'
+				})
+			},
+			nav(url) {
+				if (!this.hasLogin) {
+					// 保存地址
+					saveUrl();
+					// 登录拦截
+					interceptor();
+				} else {
+					uni.navigateTo({
+						url
+					});
+				}
+			},
+			loadData(source) {
+				let that = this
+				if (that.loadingType == 'loading' || that.loadingType == 'noMore') {
+					return
+				}
+				lock({
+					page: that.page,
+					limit: that.limit,
+					id: that.id,
+				}).then(res => {
+					let list = res.data.list.map(
+						(res) => {
+							res.bfb = +(res.join * 100 / res.stock).toFixed(2);
+							return res
+						}
+					)
+					that.list = that.list.concat(list)
+					that.page++
+					if (list.length == that.limit) {
+						that.loadingType = 'more'
+					} else {
+						that.loadingType = 'noMore'
+					}
+					that.loaded = true
+				})
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	.all {
+		width: 750rpx;
+		height: 100%;
+		background-color: #000000;
+		padding-top: var(--status-bar-height);
+	}
+
+	.top {
+		padding-top: 40rpx;
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #ffffff;
+		text-align: center;
+	}
+
+	.img {
+		width: 690rpx;
+		height: 250rpx;
+		margin: 20rpx 30rpx;
+	}
+
+	.my {
+		background-color: #191a1f;
+		margin: 0 30rpx;
+		display: flex;
+		color: #FFF;
+		padding: 20rpx 30rpx;
+		border-radius: 18rpx;
+
+		.titleTip {
+			width: 40rpx;
+			height: 40rpx;
+		}
+
+		.right {
+			width: 16rpx;
+			height: 26rpx;
+		}
+	}
+
+	.buttom {
+		background-color: #191a1f;
+		border-radius: 18rpx;
+		margin: 30rpx;
+		padding: 30rpx;
+		line-height: 1;
+
+		.le {
+			font-size: 20rpx;
+
+			.le1 {
+				font-weight: 800;
+				color: #feb041;
+				margin-bottom: 15rpx;
+				
+				&.qt {
+					padding-top: 15rpx;
+				}
+				
+				&.ze {
+					padding-top: 26rpx;
+				}
+
+				&.title {
+					font-size: 33rpx;
+					color: #ffffff;
+				}
+			}
+
+			// .le2 {
+			// 	.line {
+			// 		width: 308rpx;
+			// 		height: 16rpx;
+			// 		background-color: rgba(235, 235, 235, 0.38);
+			// 		border-radius: 99rpx;
+			// 		overflow: hidden;
+
+			// 		.line-action {
+			// 			height: 100%;
+			// 			width: 100%;
+			// 			border-radius: 99rpx;
+			// 			background-color: #FEB041;
+			// 		}
+			// 	}
+			// }
+		}
+
+		.r1 {
+			font-size: 47rpx;
+			font-weight: 800;
+			color: #FF0102;
+		}
+
+		.r2 {
+			font-size: 21rpx;
+			font-weight: 500;
+			color: #999999;
+		}
+
+		.add-buttom {
+			background: #feb041;
+			border-radius: 6rpx;
+			font-size: 21rpx;
+			font-weight: 800;
+			color: #191a1f;
+			padding: 10rpx 20rpx;
+			text-align: center;
+		}
+	}
+</style>

+ 474 - 0
pages/index/user.vue

@@ -0,0 +1,474 @@
+<template>
+	<view class="container">
+		<view class="top">
+			<view class="my">{{$t('home.d4')}}</view>
+			<view class="userinfo flex">
+				<view class="flex" @click="navTo('/pages/user/set/userinfo')">
+					<image class="image margin-r-10" :src="userInfo.avatar || '/static/error/missing-face.png'"
+						mode="scaleToFill">
+					</image>
+					<view class="info">
+						<view class="infor margin-b-20">{{ user.nickname || '游客' }}</view>
+						<view class="uservip flex-start" v-if="user.vip">
+							<text>
+								{{ user.vip_name}}
+							</text>
+							<image class="vipIcon" :src="user.vip_icon" mode="scaleToFill"></image>
+						</view>
+					</view>
+				</view>
+				<image @click="showY" class="inf" src="../../static/shouye/userinfo.png" mode="scaleToFill"></image>
+			</view>
+		</view>
+		<!-- 余额 -->
+		<view class="body">
+			<template v-if="hasLogin">
+				<view v-if="show" class="yue margin-b-30">
+					<view class="flex">
+						<view class="item">
+							<view class="te flex-start">
+								<image class="tip margin-r-10" src="../../static/icon/user-U.png" mode="scaleToFill">
+								</image>
+								<text>
+									USDT
+								</text>
+							</view>
+							<view class="tex">
+								{{userWallet}}
+							</view>
+							<!-- <view class="texmoney">
+								≈¥{{userWalletRmb}}
+							</view> -->
+						</view>
+						<view class="item">
+							<view class="te flex-start">
+								<image class="tip margin-r-10" src="../../static/icon/user-R.png" mode="scaleToFill">
+								</image>
+								<text>
+									PKR
+								</text>
+							</view>
+							<view class="tex">
+								{{userPKR}}
+							</view>
+							<!-- <view class="texmoney">
+								≈¥{{userPKRRmb}}
+							</view> -->
+						</view>
+					</view>
+					<view class="btn margin-t-30 flex">
+						<button @click="navTo('/pages/user/money/recharge')" class="btn1">
+							<text>{{$t('user.a7')}}</text>
+						</button>
+						<button @click="navTo('/pages/user/money/withdrawal')" class="btn1">
+							<text>{{$t('user.a6')}}</text>
+						</button>
+					</view>
+				</view>
+				<view v-else class="yue1 margin-b-30">
+					<view class="tj">{{$t('user.a1')}}</view>
+					<view class="tj-item flex ">
+						<view class="lj">{{$t('user.a4')}}{{$t('user.a7')}}</view>
+						<view class="ljsu">{{userInfo.sum_recharge || 0}}</view>
+					</view>
+					<view class="tj-item flex">
+						<view class="lj">{{$t('user.a4')}}{{$t('user.a6')}}</view>
+						<view class="ljsu">{{userInfo.sum_extract || 0}}</view>
+					</view>
+					<view class="tj-item flex">
+						<view class="lj">{{$t('user.a8')}}</view>
+						<view class="ljsu">{{sum_win || 0}}</view>
+					</view>
+					<view class="tj-item flex">
+						<view class="lj">{{$t('user.a9')}}</view>
+						<view class="ljsu">{{sum_bet || 0}}</view>
+					</view>
+					<view class="tj-item flex">
+						<view class="lj">{{$t('user.a10')}}</view>
+						<view class="ljsu">{{group_sum_bet || 0}}</view>
+					</view>
+				</view>
+			</template>
+			<!-- 列表 -->
+			<view class="gj">
+				{{$t('user.b1')}}
+			</view>
+			<view class="user-list flex" @click="navTo('/pages/user/money/team')">
+				<image src="../../static/shouye/yue.png" mode="scaleToFill" class="left-img"></image>
+				<view class="item-name">
+					{{$t('user.b2')}}
+				</view>
+				<image src="../../static/icon/back.png" mode="scaleToFill" class="right-img"></image>
+			</view>
+
+			<!-- 额外添加 -->
+			<view class="user-list flex" @click="navTo('/pages/user/shareQrCode')">
+				<image src="../../static/shouye/money.png" mode="scaleToFill" class="left-img"></image>
+				<view class="item-name">
+					{{$t('user.b3')}}
+				</view>
+				<image src="../../static/icon/back.png" mode="scaleToFill" class="right-img"></image>
+			</view>
+			<!-- 额外添加 -->
+			<view class="user-list flex" @click="navTo('/pages/user/vip/tabulation')">
+				<image src="../../static/shouye/liebiao.png" mode="scaleToFill" class="left-img"></image>
+				<view class="item-name">
+					{{$t('user.b4')}}
+				</view>
+				<image src="../../static/icon/back.png" mode="scaleToFill" class="right-img"></image>
+			</view>
+			<view class="user-list flex" @click="copyShareLink">
+				<image src="../../static/shouye/liebiao.png" mode="scaleToFill" class="left-img"></image>
+				<view class="item-name">
+					{{$t('user.b5')}}
+				</view>
+				<image src="../../static/icon/back.png" mode="scaleToFill" class="right-img"></image>
+			</view>
+			<!-- <view class="user-list flex" @click="openKf()">
+				<image src="../../static/shouye/liuyan.png" mode="scaleToFill" class="left-img"></image>
+				<view class="item-name">
+					{{$t('user.b6')}}
+				</view>
+				<image src="../../static/icon/back.png" mode="scaleToFill" class="right-img"></image>
+			</view> -->
+			<!-- <view class="user-list flex" @click="navTo('/pages/user/set/transaction')">
+				<image src="../../static/shouye/jiaoyi.png" mode="scaleToFill" class="left-img"></image>
+				<view class="item-name">
+					{{$t('user.b7')}}
+				</view>
+				<image src="../../static/icon/back.png" mode="scaleToFill" class="right-img"></image>
+			</view> -->
+			<!-- <view class="user-list flex" @click="navTo('/pages/public/login')">
+				<image src="../../static/shouye/tuichu.png" mode="scaleToFill" class="left-img"></image>
+				<view class="item-name">
+					{{$t('user.b8')}}
+				</view>
+				<image src="../../static/icon/back.png" mode="scaleToFill" class="right-img"></image>
+			</view> -->
+
+			<!-- 跳转到联系客服 -->
+			<view class="user-list flex" @click="nav()">
+				<image src="../../static/shouye/yue.png" mode="scaleToFill" class="left-img"></image>
+				<view class="item-name">
+					{{$t('user.a2')}}
+				</view>
+				<image src="../../static/icon/back.png" mode="scaleToFill" class="right-img"></image>
+			</view>
+			<!-- todo -->
+			<view class="user-list flex" @click="navTo('/pages/user/set/set')">
+				<image src="../../static/shouye/shezhi.png" mode="scaleToFill" class="left-img"></image>
+				<view class="item-name">
+					{{$t('user.b9')}}
+				</view>
+				<image src="../../static/icon/back.png" mode="scaleToFill" class="right-img"></image>
+			</view>
+
+		</view>
+		<taber tab='user'></taber>
+	</view>
+</template>
+<script>
+	import {
+		getIndex,
+	} from "@/api/index.js";
+
+	import {
+		gameWallet,
+	} from "@/api/game.js";
+	import taber from "@/components/footer/footer.vue";
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex';
+	import {
+		getUserInfo,
+		getUser
+	} from '@/api/user.js';
+	import {
+		saveUrl,
+		interceptor
+	} from '@/utils/loginUtils.js';
+	export default {
+		components: {
+			taber
+		},
+		data() {
+			return {
+				current: 2,
+				show: true,
+				userWallet: 0, //余额 
+				userWalletRmb: 0,
+				userPKR: 0,
+				userPKRRmb: 0,
+				extractTotalPrice: '', //累计体现
+				sum_win: '', //累计收益
+				sum_bet: '', //个人交易量
+				group_sum_bet: '', // 团队交易量
+				user: {},
+				service: ""
+			};
+		},
+		onShow() {
+			// 判断是否已经登录
+			if (this.hasLogin) {
+				this.getUserWallet();
+				this.getUser();
+			}
+			this.loadBaseData();
+			this.getIndex()
+		},
+		computed: {
+			...mapState('user', ['hasLogin', 'userInfo']),
+			...mapState(['baseURL', 'urlFile']),
+		},
+		methods: {
+			...mapMutations('user', ['setUserInfo']),
+			copyShareLink() {
+				if (!this.hasLogin) {
+					// 保存地址
+					saveUrl();
+					// 登录拦截
+					interceptor();
+				} else {
+					uni.setClipboardData({
+						data: this.baseURL + this.urlFile + '/#/pages/index/index?spread=' + this.user.account,
+						success: function() {
+							//调用方法成功
+							console.log("success");
+						},
+					});
+				}
+			},
+			showY() {
+				this.show = !this.show
+			},
+			async getIndex() {
+				const res = await getIndex()
+				this.service = res.data.service
+			},
+			// 统计表
+			async getUser() {
+				const res = await getUser();
+				this.user = res.data;
+				this.recharge = res.data.recharge;
+				this.extractTotalPrice = res.data.extractTotalPrice;
+				this.sum_win = res.data.sum_win.toFixed(2);
+				this.sum_bet = res.data.sum_bet
+				this.group_sum_bet = res.data.group_sum_bet
+			},
+			// 跳转到联系客服
+			nav() {
+				window.location.href = this.service
+			},
+			// 获取用户余额信息
+			getUserWallet() {
+				gameWallet().then((res) => {
+					const balance = Number(res.data.back.USDT.money.money);
+					this.userWallet = +balance.toFixed(2);
+					this.userWalletRmb = Number(res.data.back.USDT.rmb);
+					this.userPKR = Number(res.data.back.PKR.money.money);
+					this.userPKRRmb = Number(res.data.back.PKR.rmb);
+					// this.userWallet = +res.data.back.USDT.money.money
+				})
+			},
+			// 加载初始数据
+			loadBaseData() {
+				const obj = this
+				getUserInfo({})
+					.then(({
+						data
+					}) => {
+						obj.setUserInfo(data);
+
+					})
+					.catch(e => {
+						console.log(e);
+					});
+
+			},
+			/**
+			 * 统一跳转接口,拦截未登录路由
+			 * navigator标签现在默认没有转场动画,所以用view
+			 */
+			navTo(url) {
+				if (!this.hasLogin) {
+					// 保存地址
+					saveUrl();
+					// 登录拦截
+					interceptor();
+				} else {
+					uni.navigateTo({
+						url
+					});
+				}
+			},
+		}
+	};
+</script>
+<style lang="scss">
+	.container {
+		height: 100%;
+		line-height: 1;
+	}
+
+	.top {
+		height: 327rpx;
+		background-color: #000000;
+		padding: 0 45rpx;
+
+		.my {
+			padding-top: 40rpx;
+			font-size: 48rpx;
+			font-weight: 500;
+			color: #FFFFFF;
+		}
+
+		.userinfo {
+			padding-top: 40rpx;
+
+			.image {
+				border-radius: 100rpx;
+				overflow: hidden;
+				width: 125rpx;
+				height: 125rpx;
+			}
+
+			.info {
+				.infor {
+					font-size: 30rpx;
+					font-weight: 500;
+					color: #FFFFFF;
+				}
+
+				.vipIcon {
+					width: 40rpx;
+					height: 40rpx;
+					margin-left: 10rpx;
+				}
+
+				.uservip {
+					font-size: 30rpx;
+					font-weight: 500;
+					color: #93794B;
+				}
+			}
+		}
+	}
+
+	.inf {
+		margin-top: 25rpx;
+		width: 48rpx;
+		height: 48rpx;
+	}
+
+	//  body
+	.body {
+		background-color: #191a1f;
+		padding: 30rpx;
+		border-top-right-radius: 60rpx;
+		border-top-left-radius: 60rpx;
+		color: #FFFFFF;
+
+		.yue {
+			text-align: center;
+			padding-top: 40rpx;
+			padding-bottom: 35rpx;
+
+			.item {
+				background-color: #000000;
+				border-radius: 30rpx;
+				padding: 30rpx;
+				text-align: left;
+				width: 48%;
+
+				.te {
+					font-size: 26rpx;
+					font-weight: 500;
+					padding-bottom: 30rpx;
+
+					.tip {
+						width: 64rpx;
+						height: 64rpx;
+					}
+				}
+
+				.tex {
+					font-size: $font-lg;
+					font-weight: bold;
+					padding-bottom: 30rpx;
+				}
+
+				.texmoney {
+					font-size: $font-lg;
+					color: $font-color-disabled;
+				}
+			}
+
+
+			.btn {
+				padding: 0 50rpx;
+
+				.btn1 {
+					min-width: 270rpx;
+					background: #FDB242;
+					border-radius: 10rpx;
+					font-size: $font-base;
+				}
+			}
+		}
+
+		.yue1 {
+			background-color: #000000;
+			padding: 30rpx;
+			color: #FFFFFF;
+			border-radius: 60rpx;
+
+			.tj {
+				font-size: 30rpx;
+				font-weight: bold;
+				text-align: center;
+			}
+
+			.tj-item {
+				padding-top: 26rpx;
+				font-size: 24rpx;
+				opacity: 0.65;
+			}
+		}
+	}
+
+	.gj {
+		margin-left: 20rpx;
+		padding-top: 10rpx;
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #FFFFFF;
+		padding-bottom: 10rpx;
+	}
+
+	.user-list {
+		background: #191a1f;
+		box-shadow: 0px 0px 20rpx 0px rgba(50, 50, 52, 0.06);
+		margin: 0 auto;
+		padding: 30rpx 25rpx;
+		border-bottom: 1px solid rgba(240, 240, 240, 0.2);
+
+		.left-img {
+			width: 40rpx;
+			height: 40rpx;
+			margin-right: 20rpx;
+		}
+
+		.item-name {
+			flex-grow: 1;
+			font-size: 29rpx;
+			font-weight: bold;
+			color: #FFF;
+		}
+
+		.right-img {
+			width: 18rpx;
+			height: 27rpx;
+		}
+	}
+</style>

+ 105 - 0
pages/introduce/game.vue

@@ -0,0 +1,105 @@
+<template>
+	<view class="background1">
+		<view class="background2">
+			<view class="title"> {{$t('game.a1')}} </view>
+			<view class="juli">
+				{{$t('game.a2')}}
+			</view>
+			<view class="neirong">
+				<view class="nr1">
+					{{$t('game.a3')}}
+				</view>
+				<view class="nr2">
+					{{$t('game.a4')}}
+				</view>
+			</view>
+			<view class="ls">
+				{{$t('game.a5')}}
+			</view>
+			<view class="liushui">
+				<view class="">
+					{{$t('game.a6')}}
+				</view>
+				
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			};
+		},
+		onLoad() {
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.a6"),
+			});
+		}
+	}
+</script>
+
+<style lang="scss">
+    .background1 {
+		position: relative;
+		height: calc(100vh - var(--status-bar-height));
+		background: url("../../static/img/youxi1.png");
+		background-size: 100% 100%;
+		background-position: 50% 50%;
+		background-repeat: no-repeat;
+	}
+
+	.background2 {
+		background:url("../../static/img/youxi2.png");
+		position: absolute;
+		background-size: 100% 100%;
+		width: 650rpx;
+		height: 960rpx;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -60%);
+	}
+	.title {
+		margin-top: 95rpx;
+		text-align: center;
+		font-size: 37rpx;
+		font-weight: bold;
+		color: #d7b271;
+	}
+	.juli {
+		margin-left: 60rpx;
+		margin-top: 70rpx;
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #201809;
+	}
+	.neirong {
+		width: 530rpx;
+		height: 100;
+		margin-left: 60rpx;
+		margin-top: 30rpx;
+	}
+	.nr1 .nr2{
+		height: 147rpx;
+		font-size: 28rpx;
+		font-weight: bold;
+		color: #201809;
+	}
+	
+	.ls {
+		margin-left: 60rpx;
+		margin-top: 70rpx;
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #201809;
+	}
+	
+	.liushui {
+		width: 530rpx;
+		height: 190rpx;
+		margin-left: 60rpx;
+		margin-top: 30rpx;
+	}
+</style>

+ 106 - 0
pages/introduce/introduce.vue

@@ -0,0 +1,106 @@
+<template>
+	<view class="background1">
+		<view class="background2">
+			<view class="wenben">
+				<view class="wenben1">
+					{{$t('introduce.a1')}}
+				</view>
+				<view class="wenben4">
+					{{$t('introduce.a4')}}
+				</view>
+				
+				<view class="xian"></view>
+				<view class="item">
+					<view class="text">
+						{{$t('introduce.a3')}}
+					</view>
+				</view>
+				<view class="wenben1 margin-t-30">
+					{{$t('introduce.a6')}}
+				</view>
+				<view class="wenben4">
+					{{$t('introduce.a2')}}
+				</view>
+				<view class="xian"></view>
+
+				<view class="item">
+					<view class="text">
+						{{$t('introduce.a5')}}
+					</view>
+
+				</view>
+			</view>
+		</view>
+	</view>
+
+</template>
+
+<script>
+	export default {
+		data() {
+			return {};
+		},
+		onLoad() {
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.a4"),
+			});
+		}
+	};
+</script>
+
+<style lang="scss">
+	.background1 {
+		position: relative;
+		height: calc(100vh - var(--status-bar-height));
+		background: url("../../static/shouye/beijing1.png");
+		background-size: 100% 100%;
+		background-position: 50% 50%;
+		background-repeat: no-repeat;
+	}
+
+	.background2 {
+		background-image: url("../../static/shouye/beijing2.png");
+		position: absolute;
+		background-size: 100% 100%;
+		width: 650rpx;
+		height: 1000rpx;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -60%);
+	}
+
+	.wenben1 {
+		text-align: center;
+		margin-top: 87rpx;
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #201809;
+		line-height: 36rpx;
+	}
+
+	.xian {
+		width: 200rpx;
+		height: 8rpx;
+		color: #000000;
+	}
+
+	.text {
+		font-size: 24rpx;
+		font-weight: bold;
+		color: #211808;
+		background-color: #FAEDD6;
+		text-align: left;
+		margin: 0 50rpx;
+		padding: 30rpx;
+		border-radius: 20rpx;
+		margin-bottom: 20rpx;
+	}
+
+	.wenben4 {
+		text-align: center;
+		margin-top: 50rpx;
+		font-size: 37rpx;
+		font-weight: bold;
+		color: #D7BB80;
+	}
+</style>

+ 57 - 0
pages/introduce/pkedetail - 副本.vue

@@ -0,0 +1,57 @@
+<template>
+	<view class="content">
+		<image src="../../static/shouye/index_logo.png" mode="scaleToFill" class="index-logo"></image>
+		<view class="title">
+			{{$t('homepledge.PKR介绍')}}
+		</view>
+		<view class="description">
+			<rich-text :nodes="$t('homepledge.description')"></rich-text>
+		</view>
+		<taber tab='information'></taber>
+	</view>
+</template>
+
+<script>
+	import taber from "@/components/footer/footer.vue";
+	export default {
+		components: {
+			taber
+		},
+		data() {
+			return {};
+		},
+		onLoad() {
+			uni.setNavigationBarTitle({
+				title: this.$t('homepledge.PKR介绍'),
+			});
+		}
+	};
+</script>
+
+<style lang="scss">
+	.content {
+		width: 750rpx;
+		background-color: $page-color-base;
+		padding-top: var(--status-bar-height);
+		padding-bottom: 30rpx;
+	}
+
+	.title {
+		color: $base-color;
+		text-align: center;
+		font-size: 58rpx;
+	
+	}
+	.index-logo {
+		width: 297rpx;
+		height: 270rpx;
+		margin: 0 226rpx;
+	}
+	.description {
+		color: #FFFFFF;
+		font-size: $font-base;
+		padding: 30rpx;
+		line-height: 2rem;
+	
+	}
+</style>

+ 100 - 0
pages/introduce/pkedetail.vue

@@ -0,0 +1,100 @@
+<template>
+	<view class="background1">
+		<view class="background2">
+			<view class="title"> {{$t('homepledge.PKR介绍')}} </view>
+			<view class="neirong">
+				<view class="nr2">
+					<rich-text :nodes="$t('homepledge.description')"></rich-text>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			};
+		},
+		onLoad() {
+			uni.setNavigationBarTitle({
+				title: this.$t('homepledge.PKR介绍'),
+			});
+		}
+	}
+</script>
+
+<style lang="scss">
+	.nr2 {
+		font-size: 24rpx;
+		font-weight: bold;
+		color: #211808;
+		background-color: #FAEDD6;
+		text-align: left;
+		padding: 30rpx;
+		border-radius: 20rpx;
+		margin-bottom: 20rpx;
+	}
+    .background1 {
+		position: relative;
+		height: calc(100vh - var(--status-bar-height));
+		background: url("../../static/img/youxi1.png");
+		background-size: 100% 100%;
+		background-position: 50% 50%;
+		background-repeat: no-repeat;
+	}
+
+	.background2 {
+		background:url("../../static/img/youxi2.png");
+		position: absolute;
+		background-size: 100% 100%;
+		width: 650rpx;
+		height: 960rpx;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -60%);
+	}
+	.title {
+		margin-top: 95rpx;
+		text-align: center;
+		font-size: 37rpx;
+		font-weight: bold;
+		color: #d7b271;
+	}
+	.juli {
+		margin-left: 60rpx;
+		margin-top: 70rpx;
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #201809;
+	}
+	.neirong {
+		width: 530rpx;
+		height: 100;
+		margin-left: 60rpx;
+		margin-top: 30rpx;
+	}
+	.nr1 .nr2{
+		height: 147rpx;
+		font-size: 28rpx;
+		font-weight: bold;
+		color: #201809;
+	}
+	
+	.ls {
+		margin-left: 60rpx;
+		margin-top: 70rpx;
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #201809;
+	}
+	
+	.liushui {
+		width: 530rpx;
+		height: 190rpx;
+		margin-left: 60rpx;
+		margin-top: 30rpx;
+	}
+</style>

+ 148 - 0
pages/introduce/promotion.vue

@@ -0,0 +1,148 @@
+<template>
+	<view class="background1">
+		<view class="background2">
+			<view class="title"> {{$t('promotion.a1')}} </view>
+			<view class="top">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg1.png" mode=""></image>
+					<view class="wen">{{$t('promotion.a2')}}</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a3')}}</view>
+			</view>
+			<view class="topt">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg2.png" mode=""></image>
+					<view class="wen">V1</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a4')}} </view>
+			</view>
+			<view class="topt">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg3.png" mode=""></image>
+					<view class="wen">V2</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a5')}}</view>
+			</view>
+			<view class="topt">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg4.png" mode=""></image>
+					<view class="wen">V3</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a6')}} </view>
+			</view>
+			<view class="topt">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg5.png" mode=""></image>
+					<view class="wen">V4</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a7')}} </view>
+			</view>
+			<view class="topt">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg6.png" mode=""></image>
+					<view class="wen">V5</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a8')}}</view>
+			</view>
+			<view class="topt">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg7.png" mode=""></image>
+					<view class="wen">V6</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a9')}}</view>
+			</view>
+			<view class="topt">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg8.png" mode=""></image>
+					<view class="wen">V7</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a10')}} </view>
+			</view>
+			<view class="topt">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg9.png" mode=""></image>
+					<view class="wen">V8</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a11')}}</view>
+			</view>
+			<view class="topt">
+				<view class="hy">
+					<image class="icon" src="../../static/icon/tg10.png" mode=""></image>
+					<view class="wen">{{$t('promotion.a12')}}</view>
+				</view>
+				<view class="wenben"> {{$t('promotion.a13')}} </view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {};
+		},
+		onLoad() {
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.a5"),
+			});
+		}
+	};
+</script>
+
+<style lang="scss">
+	.background1 {
+		position: relative;
+		width: 750rpx;
+		height: 2600rpx;
+		background: url("../../static/img/tuiguang2.png");
+		background-size: 100% 100%;
+		background-position: 50% 50%;
+		background-repeat: no-repeat;
+	}
+
+	.background2 {
+		background: url("../../static/img/tuiguang1.png");
+		position: absolute;
+		background-size: 100% 100%;
+		width: 650rpx;
+		height: 2250rpx;
+		top: 53%;
+		left: 50%;
+		transform: translate(-50%, -60%);
+	}
+	.topt {
+		margin-top: -50rpx;
+	}
+	.title {
+		margin-top: 95rpx;
+		margin-left: 253rpx;
+		font-size: 37rpx;
+		font-weight: bold;
+		color: #d7b271;
+	}
+	.hy {
+		display: flex;
+		justify-content: start;
+		margin-top: 70rpx;
+		.icon {
+			width: 66rpx;
+			height: 49rpx;
+			margin-left: 60rpx;
+		}
+		.wen {
+			padding-left: 20rpx;
+			font-size: 36rpx;
+			font-weight: bold;
+			color: #201809;
+		}
+		
+	}
+	.wenben {
+		margin: 20rpx 20rpx 0 60rpx;
+		height: 100%;
+		font-size: 28rpx;
+		font-weight: bold;
+		color: #201809;
+	}
+	
+</style>

+ 349 - 0
pages/myPledge/myPledge.vue

@@ -0,0 +1,349 @@
+<template>
+	<view class="all">
+		<view class="top padding-v-30 padding-c-30">
+			<view class="zhiya padding-b-10"> {{ $t("myple.u1") }} </view>
+			<view class="zhiyashu">
+				<text class="shu">{{navList[tabCurrentIndex].sum|getMoneyStyle}}</text>
+				<text class="wen padding-l-10">USDT</text>
+			</view>
+		</view>
+		<view class="navbar flex">
+			<view v-for="(item, index) in navList" :key="index" class="nav-item flex-center"
+				:class="{ current: tabCurrentIndex === index }" @click="tabClick(index)">{{ item.text }}</view>
+		</view>
+		<view class="title-box flex">
+			<view class="title">
+				<text>{{ $t("myple.u4") }}</text>
+			</view>
+			<view class="title">
+				<text>{{ $t("myple.u5") }}</text>
+			</view>
+			<view class="title">
+				<text>{{ $t("myple.u6") }}</text>
+			</view>
+			<view class="title">
+				<text>{{ $t("myple.u7") }}</text>
+			</view>
+			<!-- <view class="title">
+				<text>{{ $t("myple.u8") }}</text>
+			</view> -->
+		</view>
+		<swiper :current="tabCurrentIndex" :style="{ height: height }" class="swiper-box" duration="300"
+			@change="changeTab">
+			<swiper-item class="tab-content padding-b-30" v-for="(tabItem, tabIndex) in navList" :key="tabIndex">
+				<scroll-view scroll-y="true" class="list-scroll-content" @scrolltolower="loadData">
+					<!-- 空白页 -->
+					<empty v-if="
+							tabItem.loaded === true &&
+							tabItem.orderList.length === 0
+						"></empty>
+					<!-- 订单列表 -->
+					<view>
+						<!-- <view class="order-item flex" > -->
+						<view class="order-item">
+							<view class="all-list" v-for="(item,ind) in navList[tabCurrentIndex].orderList" :key="ind">
+								<view class="list flex padding-v-20">
+									<view class="list-item">
+										<view class="item"> {{item.num}} </view>
+										<view class="item"> USDT </view>
+									</view>
+									<view class="list-item">
+										<view class="item"> {{item.income}} </view>
+										<view class="item"> PKR </view>
+									</view>
+									<view class="list-item">
+										<view class="item">
+											{{item.day}}天
+										</view>
+									</view>
+									<view class="list-item">
+										<view class="l-item">{{item.add_time[0]}} </view>
+										<view class="l-item">
+											{{item.add_time[1]}}
+										</view>
+									</view>
+									<!-- <view class="list-item">
+										<view class="l-item">{{item.send_time[0]}}</view>
+										<view class="l-item">
+											{{item.send_time[1]}}
+										</view>
+									</view> -->
+								</view>
+							</view>
+							<!-- <view class="money">
+								<view>{{ (item.pm == 0 ? '-' : '+') + item.number * 1 }}</view>
+							</view> -->
+						</view>
+					</view>
+				</scroll-view>
+			</swiper-item>
+		</swiper>
+	</view>
+</template>
+
+<script>
+	import {
+		getLock
+	} from "@/api/mypledge.js";
+	import empty from "@/components/empty";
+	import {
+		getTime
+	} from '@/utils/rocessor.js';
+	import {
+		getMoneyStyle
+	} from "@/utils/rocessor.js";
+	export default {
+		filters: {
+			getMoneyStyle,
+		},
+		components: {
+			empty,
+		},
+		onReady(res) {
+			var _this = this;
+			uni.getSystemInfo({
+				success: resu => {
+					const query = uni.createSelectorQuery();
+					query.select('.swiper-box').boundingClientRect();
+					query.exec(function(res) {
+						_this.height = resu.windowHeight - res[0].top + 'px';
+					});
+				},
+				fail: res => {}
+			});
+		},
+		data() {
+			return {
+				height: "",
+				tabCurrentIndex: 0,
+				navList: [{
+						state: 1,
+						text: this.$t('myple.u2'),
+						loadingType: "more",
+						orderList: [],
+						page: 1, //当前页数
+						limit: 10, //每次信息条数
+						loaded: false,
+						sum:''
+					},
+					{
+						state: 2,
+						text: this.$t('myple.u3'),
+						loadingType: "more",
+						orderList: [],
+						page: 1, //当前页数
+						limit: 10, //每次信息条数
+						loaded: false,
+						sum:''
+					},
+				],
+			};
+		},
+		onLoad(options) {
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.a1"),
+			});
+		},
+		onShow() {
+			this.loadData();
+		},
+		methods: {
+			getTime,
+			toBack() {
+				uni.switchTab({
+					url: "/pages/pledge/pledge",
+				});
+			},
+			// 页面跳转
+			navto(e) {
+				uni.navigateTo({
+					url: e,
+				});
+			},
+			//获取收入支出信息
+			async loadData(source) {
+				const that = this;
+				//这里是将订单挂载到tab列表下
+				let index = that.tabCurrentIndex;
+				let navItem = that.navList[index];
+				let state = navItem.state;
+				if (source === 'tabChange' && navItem.loaded === true) {
+					//tab切换只有第一次需要加载数据
+					return;
+				}
+				if (navItem.loadingType === 'loading') {
+					//防止重复加载
+					return;
+				}
+				if (navItem.loadingType === 'noMore') {
+					//防止重复加载
+					return;
+				}
+				// 修改当前对象状态为加载中
+				navItem.loadingType = 'loading';
+
+				getLock({
+						status: state,
+						page: navItem.page,
+						limit: navItem.limit
+					})
+					.then(({
+						data
+					}) => {
+						// 保存我的总金额
+						navItem.sum = data.sum;
+
+						let arr = data.list.map(e => {
+							e.add_time = that.getTime(e.add_time).split(" ")
+							e.send_time = that.getTime(e.send_time).split(" ")
+							e.income = Number(e.income);
+							e.num = Number(e.num);
+							return e;
+						});
+						navItem.orderList = navItem.orderList.concat(arr);
+						if (navItem.limit == data.length) {
+							navItem.page++;
+							//判断是否还有数据, 有改为 more, 没有改为noMore
+							navItem.loadingType = 'more';
+							return;
+						} else {
+							//判断是否还有数据, 有改为 more, 没有改为noMore
+							navItem.loadingType = 'noMore';
+						}
+						uni.hideLoading();
+						that.$set(navItem, 'loaded', true);
+					})
+					.catch(e => {
+						console.log(e);
+					});
+			},
+			//swiper 切换
+			changeTab(e) {
+				this.tabCurrentIndex = e.target.current;
+				this.loadData("tabChange");
+			},
+			//顶部tab点击
+			tabClick(index) {
+				this.tabCurrentIndex = index;
+			},
+		},
+	};
+</script>
+
+<style lang="scss">
+	.all {
+		line-height: 1;
+	}
+
+	.top {
+		margin: 0 30rpx;
+		height: 138rpx;
+		background-color: #191a1f;
+		font-weight: bold;
+		color: #ffffff;
+		border-radius: 20rpx;
+
+		.zhiya {
+			font-size: $font-sm;
+			color: #757c8f;
+		}
+
+		.zhiyashu {
+			.shu {
+				font-size: $font-lg;
+			}
+
+			.wen {
+				font-size: $font-base;
+			}
+		}
+	}
+
+	.swiper-box {
+		margin: 0 30rpx;
+	}
+
+	.navbar {
+		margin: 20rpx 30rpx 0 30rpx;
+		border-top-right-radius: 20rpx;
+		border-top-left-radius: 20rpx;
+		height: 88rpx;
+		padding: 0 5px;
+		background: #191a1f;
+		border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+
+		.nav-item {
+			flex: 1;
+			height: 100%;
+			font-size: 15px;
+			color: #999999;
+			position: relative;
+
+			&.current {
+				color: #fff;
+
+				&:after {
+					content: "";
+					position: absolute;
+					left: 50%;
+					bottom: 0;
+					transform: translateX(-50%);
+					width: 44px;
+					height: 0;
+					border-bottom: 2px solid $color-yellow;
+				}
+			}
+		}
+	}
+
+	.tab-content {
+		.list-scroll-content {
+			background: #191a1f;
+			border-bottom-right-radius: 20rpx;
+			border-bottom-left-radius: 20rpx;
+			height: 100%;
+			overflow:hidden;
+		}
+	}
+
+	// 列表样式
+	.title-box {
+		padding: 20rpx 0;
+		background: #191a1f;
+		margin: 0 30rpx;
+		justify-content: space-around;
+		border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+
+		.title {
+			width: 20%;
+			font-size: 22rpx;
+			color: $font-color-light;
+			text-align: center;
+		}
+	}
+
+	.all-list {
+		.list {
+			border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+			justify-content: space-around;
+
+			.list-item {
+				color: #ffffff;
+				width: 20%;
+				text-align: center;
+				flex-shrink: 0;
+
+				.item {
+					font-size: 22rpx;
+					font-weight: bold;
+				}
+
+				.l-item {
+					font-size: 18rpx;
+				}
+
+			}
+		}
+
+	}
+</style>

+ 398 - 0
pages/myPledge/zyXingqing.vue

@@ -0,0 +1,398 @@
+<template>
+	<view class="all">
+		<view class="shang padding-v-30 padding-c-30 position-relative">
+			<image class="img" src="../../static/img/xq6.png" mode="scaleToFill"></image>
+			<view class="tz padding-b-30">{{base.name}}</view>
+			<view class="sy flex-start padding-b-10">
+				<view class="syl">{{$t('zy.m0')}}:{{base.day_get}}%</view>
+			</view>
+			<view class="sj flex margin-t-30 position-relative">
+				<view class="sj1">
+					<view class="sz">{{base.single_time_max*1}}</view>
+					<view class="wz">{{$t('zy.m1')}}</view>
+				</view>
+				<view class="sj1">
+					<view class="sz">{{base.single_time_max*1}}</view>
+					<view class="wz">{{$t('zy.m3')}}</view>
+				</view>
+				<view class="sj1">
+					<view class="sz">{{base.day}}</view>
+					<view class="wz">{{$t('zy.m2')}}</view>
+				</view>
+				<view class="sj1">
+					<view class="sz">{{base.single_time_min*1}}</view>
+					<view class="wz">{{$t('zy.m4')}}</view>
+				</view>
+			</view>
+		</view>
+
+		<view class="sygc margin-t-20 padding-v-30 padding-c-30">
+			<view class="gc padding-b-30">{{$t('zy.m5')}}</view>
+			<view class="an flex padding-c-30">
+				<view class="an1"></view>
+				<view class="xian"></view>
+				<view class="an1"></view>
+				<view class="xian"></view>
+				<view class="an1"></view>
+			</view>
+			<view class="wenben padding-t-30 flex padding-c-30">
+				<view class="wb">
+					<view class="wen">{{$t('zy.m6')}}</view>
+					<view class="wen padding-t-10">{{$t('zy.m7')}}</view>
+				</view>
+				<view class="wb">
+					<view class="wen text-center">{{$t('zy.m8')}}</view>
+					<view class="wen padding-t-10 text-center">{{$t('zy.m9')}}</view>
+				</view>
+				<view class="wb">
+					<view class="wen text-right">{{$t('zy.m10')}}</view>
+					<view class="wen padding-t-10 text-right">{{$t('zy.m11')}}</view>
+				</view>
+			</view>
+			<view class="icon-box padding-t-30">
+				<view class="icon flex-start">
+					<image class="ic" src="../../static/img/xq1.png" mode=""></image>
+					<view class="jiaru">{{$t('zy.m12')}}</view>
+				</view>
+
+				<view class="icon flex-start">
+					<image class="ic" src="../../static/img/xq4.png" mode=""></image>
+					<view class="jiaru">{{$t('zy.m13')}}</view>
+				</view>
+
+				<view class="icon flex-start">
+					<image class="ic" src="../../static/img/xq3.png" mode=""></image>
+					<view class="jiaru">
+						{{$t('zy.m14')}}:{{base.single_time_max*1}}*{{base.day_get}}%*{{base.day}}
+					</view>
+				</view>
+
+				<view class="icon flex-start">
+					<image class="ic" src="../../static/img/xq2.png" mode=""></image>
+					<view class="jiaru">{{$t('zy.m15')}}:{{allMoney}}</view>
+				</view>
+			</view>
+		</view>
+		<view class="yue flex margin-t-20">
+			<view class="flex">
+				<image class="qianbao" src="../../static/img/xq5.png" mode=""></image>
+				<view class="ye padding-l-20">{{$t('zy.m17')}}</view>
+			</view>
+			<view class="flex">
+				<view class="dangqian">{{$t('zy.m18')}}:</view>
+				<view class="dqs">{{userWallet}} USDT</view>
+			</view>
+		</view>
+		<view class="aaa"></view>
+
+		<view class="liji">
+			<view class="jr" @click="joinNumOpen">
+				<view class="jia">{{$t('zy.m19')}}</view>
+			</view>
+		</view>
+		<uni-popup type="bottom" ref="popup">
+			<inputPassword @commit='KeyInfo' @colse='colsePayPassword'></inputPassword>
+		</uni-popup>
+		<uni-popup ref="inputDialog" type="dialog">
+			<uni-popup-dialog ref="inputClose" mode="input" :title="$t('zy.b1')" :value="num" :placeholder="$t('zy.b2')"
+				@confirm="joinNum" :confirmText="$t('zy.b3')" :cancelText="$t('zy.b4')"></uni-popup-dialog>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import {
+		lockDetail,
+		lockJoin
+	} from "@/api/mypledge.js"
+	import {
+		gameWallet
+	} from "@/api/game.js";
+	import inputPassword from "@/components/input-password/input-password.vue";
+	export default {
+		components: {
+			inputPassword
+		},
+		data() {
+			return {
+				id: '',
+				base: {},
+				userWallet: '',
+				allMoney: '',
+				// 保存支付密码
+				password: '',
+				//购买的数量
+				num: '',
+			};
+		},
+		
+		onLoad(option) {
+			this.id = option.id;
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.b5"),
+			});
+			// 加载数据
+			this.lockDetail();
+			this.gameWallet();
+		},
+		methods: {
+			// 关闭支付弹窗
+			colsePayPassword() {
+				this.$refs.popup.close();
+			},
+			KeyInfo(val) {
+				this.password = val;
+				this.colsePayPassword();
+				this.joinLock();
+			},
+			// 打开输入弹窗
+			joinNumOpen() {
+				this.$refs.inputDialog.open();
+			},
+			// 输入的金额
+			joinNum(e) {
+				if (isNaN(Number(e))) {
+					uni.showToast({
+						title: this.$t("zy.b5"),
+						icon: "error"
+					})
+					return
+				}
+				this.num = e;
+				this.$refs.popup.open();
+				console.log(e, '233');
+			},
+			// 购买质押
+			joinLock() {
+				const that = this;
+				const data = {
+					id: that.id,
+					number: that.num,
+					trade_password: that.password
+				}
+				// 初始化数量
+				that.num = '';
+				lockJoin(data).then(
+					(res) => {
+						uni.showToast({
+							title: this.$t("zy.b6"),
+						})
+						that.gameWallet();
+					}
+				).then((err) => {
+					console.log(err);
+				})
+			},
+			gameWallet() {
+				gameWallet().then((res) => {
+
+					this.userWallet = +res.data.back.USDT.money.money
+				})
+			},
+			lockDetail() {
+				const that = this;
+				lockDetail({
+					id: that.id
+				}).then(
+					(res) => {
+						that.base = res.data.data;
+						that.allMoney = that.base.single_time_max * (that.base.day_get * 1) * that.base.day /
+							100;
+						that.allMoney = that.allMoney+' PKR';
+					}
+				).catch(
+					(res) => {
+						console.log(res);
+					}
+				)
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page {
+		background-color: #191a1f;
+		// background-color: #000000;
+	}
+
+	.all {
+		line-height: 1;
+		padding-bottom: 190rpx;
+	}
+
+	.shang {
+		font-weight: 800;
+		background-color: $page-color-base;
+
+		.tz {
+			font-size: 33rpx;
+			color: #FFFFFF;
+		}
+
+		.sy {
+			.syl {
+				background: #FEB041;
+				border-radius: 10rpx;
+				font-size: 21rpx;
+				color: #000000;
+				padding: 10rpx;
+			}
+		}
+
+		.sj {
+			font-weight: 800;
+			text-align: center;
+
+			.sj1 {
+				width: 25%;
+
+				.sz {
+					font-size: 40rpx;
+					color: #FFFFFF;
+				}
+
+				.wz {
+					margin-top: 20rpx;
+					font-size: 22rpx;
+					color: #999999;
+					padding-bottom: 20rpx;
+				}
+			}
+		}
+
+		.img {
+			position: absolute;
+			width: 325rpx;
+			height: 285rpx;
+			top: 0rpx;
+			right: 40rpx;
+		}
+	}
+
+	.sygc {
+		background-color: $page-color-base;
+
+		.gc {
+			font-size: 28rpx;
+			font-weight: 800;
+			color: #FFFFFF;
+		}
+
+		.an {
+			.an1 {
+				width: 24rpx;
+				height: 24rpx;
+				border: 4px solid #FEB041;
+				border-radius: 12rpx;
+			}
+
+			.xian {
+				flex-grow: 1;
+				height: 1rpx;
+				background: #fff;
+			}
+		}
+	}
+
+	.wenben {
+		background-color: $page-color-base;
+
+		.wb {
+			width: 33.3%;
+
+			.wen {
+				font-size: 22rpx;
+				font-weight: 500;
+				color: #999999;
+			}
+		}
+	}
+
+	.icon-box {
+		background-color: $page-color-base;
+
+		.icon:nth-child(2n-1) {
+			background: #161616;
+		}
+
+		.icon {
+			margin: 0 30rpx;
+			border-radius: 10rpx;
+			padding: 20rpx;
+
+			.ic {
+				width: 38rpx;
+				height: 36rpx;
+
+			}
+
+			.jiaru {
+				padding-left: 20rpx;
+				height: 23rpx;
+				font-size: 24rpx;
+				color: #FFFFFF;
+			}
+		}
+	}
+
+	.jine {
+		background-color: $page-color-base;
+		font-weight: 800;
+		padding: 30rpx;
+
+		.je {
+			font-size: 28rpx;
+			color: #999999;
+		}
+
+		.jes {
+			font-size: 74rpx;
+			color: #FEB041;
+		}
+	}
+
+
+
+	.yue {
+		background-color: $page-color-base;
+		width: 750rpx;
+		color: #FFFFFF;
+		font-size: 29rpx;
+		padding: 30rpx;
+
+		.qianbao {
+			width: 80rpx;
+			height: 64rpx;
+		}
+
+		.ye {}
+
+		.dangqian {}
+
+		.dqs {
+			color: #FEB041;
+		}
+	}
+
+	.liji {
+		padding: 40rpx 30rpx;
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		background-color: $page-color-base;
+		.jr {
+			background: linear-gradient(90deg, #feb041 0%, #feb041 100%);
+			border-radius: 10rpx;
+			padding: 30rpx;
+			text-align: center;
+		}
+
+		.jia {
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #040404;
+		}
+	}
+</style>

+ 21 - 0
pages/public/forget.vue

@@ -0,0 +1,21 @@
+<template>
+	<view class="container">
+		
+	</view>
+</template>
+<script>
+export default {
+	data() {
+		return {
+		};
+	},
+	onLoad() {},
+	methods: {
+		//发送验证码
+	}
+};
+</script>
+
+<style lang="scss">
+
+</style>

+ 468 - 0
pages/public/login.vue

@@ -0,0 +1,468 @@
+<template>
+	<view class="container">
+		<view class="container_text">
+			<image class="banner-img" src="/static/img/logo.png" mode="widthFix"></image>
+		</view>
+		<view class="login_text">
+			<view class="login_input flex">
+				<view class="login_img">
+					<image src="/static/icon/ze.png"></image>
+				</view>
+				<view class="login_name">
+					<input class="uni-input" v-model="account" focus :placeholder="$t('login.a1')" />
+				</view>
+			</view>
+			<view class="login_input flex">
+				<view class="login_img">
+					<image src="/static/icon/ze2.png"></image>
+				</view>
+				<view class="login_name"><input class="uni-input" type="password" v-model="passward" focus
+						:placeholder="$t('login.a3')" /></view>
+			</view>
+			<view><button type="green" class="uni-button uni-button-green" @click="toLogin">{{$t('login.a4')}}</button>
+			</view>
+			<view><button type="green" class="uni-button uni-button-green uni-button-green-plain" plain="true"
+					hover-class="none" @click="register">{{$t('login.a7')}}</button></view>
+			<navigator url="./forget">
+				<view class="forget">{{$t('login.b2')}}</view>
+			</navigator>
+			<!-- #ifdef H5 -->
+			<view class="flex">
+				<button class="uni-button loadapp" @click="domApp('apk')">APK下载</button>
+				<button class="uni-button loadapp" @click="domApp('ios')">IOS下载</button>
+			</view>
+			<!-- #endif -->
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapMutations
+	} from 'vuex';
+	import {
+		login
+	} from '@/api/login.js';
+	import {
+		getUserInfo
+	} from '@/api/user.js';
+	// #ifdef APP-PLUS
+	// applelogin接口需要开发编写,基础项目中可能没有
+	import {
+		applelogin
+	} from '@/api/set.js';
+	// loginWx接口需要开发编写,基础项目中可能没有
+	import {
+		loginWx
+	} from '@/api/login.js';
+	// #endif
+	// #ifdef H5
+	import {
+		loginWinxin
+	} from '@/utils/wxAuthorized';
+	import {
+		getAppVersion
+	} from '@/api/index.js'
+	// #endif
+
+	export default {
+		data() {
+			return {
+				// account: '13245678911' ,// 账号
+				// passward: '132456', //密码
+				account: '',
+				passward: '',
+				// #ifdef APP-PLUS
+				is_ios: false, //判断是否为ios手机
+				is_apple_login: false, //是否有ios授权登录功能
+				// #endif
+			};
+		},
+		onLoad() {
+			let obj = this;
+			uni.setNavigationBarTitle({
+				title: this.$t("login.a4"),
+			});
+			// #ifdef APP-PLUS
+			let system = uni.getStorageSync('platform');
+			// 判断是否为ios
+			if (system == 'ios') {
+				obj.is_ios = true;
+			}
+			uni.getSystemInfo({
+				success(e) {
+					if (+e.system.split('.')[0] >= 13) {
+						obj.is_apple_login = true;
+					}
+				}
+			})
+			// #endif
+		},
+		methods: {
+			...mapMutations('user', ['setUserInfo', 'login']),
+			// #ifdef H5
+			domApp(type) {
+				console.log('111');
+				const bool = navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger';
+				if (bool) {
+					uni.showModal({
+						// title: '提示',
+						title: this.$t("enter.a7"),
+						// content: '无法在微信中下载,请用浏览器打开下载',
+						content: this.$t("login.c2"),
+						showCancel: false,
+					});
+				} else {
+					if (type == 'apk') {
+						getAppVersion().then((res) => {
+							console.log(res, 'res');
+							window.open(res.data.apk);
+						}).catch((err) => {
+							console.log(err, 'err');
+						})
+						return
+					}
+					if (type == "ios") {
+						window.open("/index/dom/iosdom.mobileconfig");
+					}
+				}
+			},
+			// #endif
+			// 微信登录
+			wecahtLogin(type) {
+				let obj = this;
+				// #ifdef H5
+				let weichatBrowser = uni.getStorageSync('weichatBrowser');
+				if (weichatBrowser) {
+					loginWinxin();
+				}
+				// #endif
+				// #ifdef APP-PLUS
+				uni.login({
+					provider: type,
+					success(e) {
+						uni.getUserInfo({
+							provider: type,
+							success(es) {
+								if (type === 'weixin') {
+									loginWx(es.userInfo)
+										.then(e => {
+											uni.setStorageSync('token', e.data.token);
+											getUserInfo({}).then(e => {
+												obj.login();
+												// 保存返回用户数据
+												obj.setUserInfo(e.data);
+												//成功跳转首页
+												uni.switchTab({
+													url: '/pages/index/index'
+												});
+											});
+										})
+										.catch(e => {
+											console.log(e);
+											uni.showModal({
+												content: JSON.stringify(e),
+												success() {},
+												fail() {}
+											});
+										});
+								}
+								if (type === 'apple') {
+									console.log(es.userInfo);
+									applelogin({
+											account: es.userInfo.openId,
+										})
+										.then(function(e) {
+											console.log(e, 'token')
+											uni.setStorageSync('token', e.data.token);
+											getUserInfo({}).then(e => {
+												obj.login();
+												// 保存返回用户数据
+												obj.setUserInfo(e.data);
+												//成功跳转首页
+												uni.switchTab({
+													url: '/pages/index/index'
+												});
+											});
+
+										})
+										.catch(function(e) {
+											console.log(e);
+										});
+								}
+
+							},
+							fail(es) {
+								uni.showModal({
+									content: JSON.stringify(es),
+									success() {
+										// obj.login();
+										// // 保存返回用户数据
+										// obj.setUserInfo(e.data);
+										// //成功跳转首页
+										// uni.switchTab({
+										// 	url: '/pages/index/index'
+										// });
+									}
+								});
+							}
+						});
+					},
+					fail(e) {
+						uni.showModal({
+							title: '提示',
+							content: JSON.stringify(e),
+							showCancel: false
+						});
+					}
+				});
+				// #endif
+			},
+			//登录
+			async toLogin() {
+				let obj = this;
+				obj.logining = true;
+				if (obj.account == '') {
+					obj.$api.msg(obj.$t("login.a1"));
+					// obj.$api.msg('132456789');
+					return;
+				}
+				if (obj.passward == '') {
+					obj.$api.msg(obj.$t("login.a3"));
+					// obj.$api.msg('132456');
+					return;
+				}
+				login({
+						account: obj.account,
+						password: obj.passward
+					})
+					.then(function(e) {
+						uni.setStorageSync('token', e.data.token);
+						getUserInfo({}).then(e => {
+							obj.login();
+							// 保存返回用户数据
+							obj.setUserInfo(e.data);
+							let ur = '';
+							let url = uni.getStorageSync('present') || '';
+							if (url != '/pages/public/login' && url) {
+								ur = uni.getStorageSync('present')
+							} else {
+								ur = '/pages/index/index';
+							}
+							//成功跳转首页
+							uni.switchTab({
+								url: ur,
+								fail(e) {
+									uni.navigateTo({
+										url: ur,
+										fail(e) {
+											uni.switchTab({
+												url: '/pages/index/index',
+											});
+										}
+									});
+								}
+							});
+						});
+					})
+					.catch(function(e) {
+						console.log(e);
+					});
+			},
+			//跳转注册页
+			register() {
+				uni.navigateTo({
+					url: `/pages/public/register`
+				});
+			},
+			// 后退
+			navBack() {
+				uni.navigateBack();
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	/* #ifdef APP-PLUS */
+
+	.ios_login {
+		width: 260rpx;
+		border-radius: 12rpx;
+		justify-content: center;
+		border: 1px solid #212121;
+		margin: 24rpx auto;
+		padding: 10rpx;
+		background-color: #212121;
+		color: #ffffff;
+
+		.loginIcon {
+			width: 50rpx;
+			height: 50rpx;
+		}
+
+		.weixin_text {
+			line-height: 1;
+			margin-left: 20rpx;
+			color: #ffffff !important;
+		}
+	}
+
+	/* #endif */
+	.ios_login {
+		width: 350rpx;
+		border-radius: 12rpx;
+		justify-content: center;
+		border: 1px solid #212121;
+		margin: 24rpx auto;
+		padding: 15rpx;
+		background-color: #212121;
+		color: #ffffff;
+		font-size: 32rpx;
+
+		.loginIcon {
+			font-size: 35rpx;
+			width: 35rpx;
+			height: 35rpx;
+		}
+
+		.weixin_text {
+			line-height: 1;
+			margin-left: 20rpx;
+			color: #ffffff !important;
+		}
+	}
+
+	page {
+		height: 100%;
+	}
+
+	.container {
+		width: 100%;
+		height: 100%;
+		background-size: 100%;
+		background-color: #000000;
+	}
+
+	.container_text {
+		width: 100%;
+		height: 500rpx;
+		top: 0rpx;
+
+		.banner-img {
+			width: 144rpx;
+			margin-top: 100rpx;
+			margin-left: 302rpx;
+		}
+	}
+
+	.login_text {
+		margin: auto 10rpx;
+		position: relative;
+		padding: 100rpx 102rpx;
+		background-color: #000000;
+		margin-top: -180rpx;
+		border-radius: 20rpx;
+
+		.login_input {
+			border-bottom: 1px solid #f0f0f0;
+			margin-bottom: 65rpx;
+
+			.login_img image {
+				height: 35rpx;
+				width: 29rpx;
+			}
+
+			.uni-input {
+				text-align: left;
+				width: 100%;
+				font-size: 28rpx !important;
+			}
+
+			.login_name {
+				margin-left: 20rpx;
+				flex-grow: 1;
+				color: #fff;
+			}
+		}
+
+		.other {
+			margin-top: 60rpx;
+
+			.fenge {
+				width: 30%;
+				height: 2rpx;
+				background-color: #eeeeee;
+			}
+
+			.qita {
+				font-size: 28rpx;
+				color: #999999;
+			}
+		}
+
+		.weixin {
+			width: 75rpx;
+			height: 75rpx;
+			margin: 25rpx auto;
+		}
+
+		.weixin image {
+			width: 100%;
+			height: 100%;
+		}
+
+		.weixin_text {
+			text-align: center;
+			font-size: 28rpx;
+			color: #999999;
+		}
+
+		.forget {
+			font-size: 28rpx;
+			width: 100%;
+			text-align: right;
+			color: #999999;
+		}
+
+		.uni-button-green {
+			color: #ffffff;
+			background-color: #feb041;
+			margin: 40rpx 10rpx;
+			border-radius: 50rpx;
+		}
+
+		.uni-button-green-plain {
+			border: 1px solid #feb041;
+			margin: 40rpx 10rpx;
+			border-radius: 50rpx;
+			color: #feb041;
+			background-color: #000000;
+		}
+
+		.uni-button {
+			height: 85rpx;
+			line-height: 85rpx;
+		}
+	}
+
+	.loginTitle {
+		position: absolute;
+		top: 250rpx;
+		width: 100%;
+		text-align: center;
+		color: #cbb174;
+		font-size: 40rpx;
+	}
+
+	/* #ifdef H5 */
+	.loadapp {
+		margin-top: 20rpx;
+		border: 1px solid #feb041;
+		background-color: transparent;
+		color: #feb041;
+		width: 45%;
+	}
+
+	/* #endif */
+</style>

+ 398 - 0
pages/public/register.vue

@@ -0,0 +1,398 @@
+<template>
+	<view class="container">
+		<view class="container_text">
+			<image class="banner-img" src="/static/img/logo.png" mode="widthFix"></image>
+		</view>
+		<view class="login_text">
+			<view class="login_input flex">
+				<view class="login_img">
+					<image src="/static/icon/ze.png"></image>
+				</view>
+				<view class="login_name"><input class="uni-input" @input="checkAccount" v-model="account" focus
+						:placeholder="$t('login.a1')" /></view>
+			</view>
+			<view class="login_input flex">
+				<view class="login_img">
+					<image src="/static/icon/ze2.png"></image>
+				</view>
+				<view class="login_name"><input class="uni-input" type="password" v-model="password" focus
+						:placeholder="$t('login.a3')" /></view>
+			</view>
+			<view class="login_input flex">
+				<view class="login_img">
+					<image src="/static/icon/ze2.png"></image>
+				</view>
+				<view class="login_name"><input class="uni-input" type="password" v-model="trade_password" focus
+						:placeholder="$t('login.b3')" /></view>
+			</view>
+			<view class="login_input flex">
+				<view class="login_img">
+					<image src="/static/icon/ze2.png"></image>
+				</view>
+				<view class="login_name"><input class="uni-input" type="text" v-model="spread" focus
+						:placeholder="$t('login.b4')" /></view>
+			</view>
+			<view class="login_input flex">
+				<view class="login_img">
+					<image src="/static/icon/ze.png"></image>
+				</view>
+				<view class="login_name flex">
+					<input class="uni-input width" v-model="captcha" focus :placeholder="$t('login.b6')" />
+					<view class="code" @click="verification">{{ countDown == 0 ? $t('login.b5') : countDown }}</view>
+				</view>
+			</view>
+			<view><button type="green" @click="register" class="uni-button uni-button-green">{{$t('login.a7')}}</button>
+			</view>
+			<view><button class="uni-button uni-button-green uni-button-green-plain" type="green" plain="true"
+					hover-class="none" @click="login">{{$t('login.a4')}}</button></view>
+			<!-- #ifdef H5 -->
+			<view class="flex">
+				<button class="uni-button loadapp" @click="domApp('apk')">APK下载</button>
+				<button class="uni-button loadapp" @click="domApp('ios')">IOS下载</button>
+			</view>
+			<!-- #endif -->
+		</view>
+	</view>
+</template>
+<script>
+	import {
+		register,
+		verify
+	} from '@/api/login.js';
+	// #ifdef H5
+	import {
+		getAppVersion
+	} from '@/api/index.js'
+	// #endif
+	export default {
+		data() {
+			return {
+				// phone: '', //用户
+				account: '', //用户
+				password: '', //密码
+				repassword: '',
+				// invitation: '', //邀请码
+				spread: '', //邀请码
+				captcha: '', //验证码
+				time: '', //保存倒计时对象
+				countDown: 0, //倒计时
+				trade_password: '', // 交易密码
+				isPhone: true, //是否为手机号,默认为true
+			};
+		},
+		onLoad(option) {
+			uni.setNavigationBarTitle({
+				title: this.$t("login.a7"),
+			});
+			// #ifndef MP
+			if (option.spread) {
+				// 存储其他邀请人
+				uni.setStorageSync('spread', option.spread);
+			}
+			// #endif
+			// #ifdef MP
+			if (option.scene) {
+				// 存储小程序邀请人
+				uni.setStorage({
+					key: 'spread_code',
+					data: option.scene
+				});
+			}
+			// #endif
+			// 获取扫码邀请人id
+			this.spread = option.spread || uni.getStorageSync('spread') || '';
+		},
+		watch: {
+			// 监听倒计时
+			countDown(i) {
+				if (i == 0) {
+					clearInterval(this.time);
+				}
+			}
+		},
+		methods: {
+			// #ifdef H5
+			domApp(type) {
+				const bool = navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger';
+				if (bool) {
+					uni.showModal({
+						// title: '提示',
+						title: this.$t("enter.a7"),
+						// content: '无法在微信中下载,请用浏览器打开下载',
+						content: this.$t("login.c2"),
+						showCancel: false,
+					});
+				} else {
+					if (type == 'apk') {
+						getAppVersion().then((res) => {
+							console.log(res, 'res');
+							window.open(res.data.apk);
+						}).catch((err) => {
+							console.log(err, 'err');
+						})
+						return
+					}
+					if(type=="ios"){
+						window.open("/index/dom/iosdom.mobileconfig");
+					}
+				}
+			},
+			// #endif
+			checkAccount() {
+				const regPhone = /^1[3|4|5|7|8][0-9]{9}$/;
+				const regEmail = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/;
+				this.isPhone = regPhone.test(this.account);
+			},
+			// 注册
+			register() {
+				let obj = this;
+				if (obj.account == '') {
+					obj.$api.msg(obj.$t("login.a1"));
+					return;
+				}
+				if (this.isPhone) {
+					if (!/^1[3|4|5|7|8][0-9]{9}$/.test(this.account)) {
+						this.$api.msg(obj.$t("safe.b8"));
+						return;
+					}
+				} else {
+					if (!/^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/.test(this.account)) {
+						this.$api.msg(obj.$t("login.b9"));
+						return;
+					}
+				}
+				if (obj.password == '') {
+					obj.$api.msg(obj.$t("reg.a9"));
+					return;
+				}
+				if (obj.trade_password == '') {
+					obj.$api.msg(obj.$t("login.b3"));
+					return;
+				}
+
+				register({
+					account: obj.account, //账号
+					captcha: obj.captcha, //验证码
+					password: obj.password, //密码
+					trade_password: obj.trade_password, // 交易密码
+					spread: this.spread //上级推广人
+				}).then(function(e) {
+					uni.showToast({
+						title: obj.$t("reg.c5"),
+						duration: 2000,
+						position: 'top'
+					});
+					uni.showModal({
+						title: obj.$t("enter.a7"),
+						content: obj.$t("login.c3"),
+						cancelText: obj.$t("zy.b4"),
+						confirmText: obj.$t("zy.b3"),
+						success: res => {
+							if(res.confirm){
+								uni.navigateTo({
+									url: '/pages/public/login'
+								});
+							}
+						},
+						fail: () => {},
+						complete: () => {}
+					});
+				});
+				//调用注册接口,成功跳转登录页
+			},
+			//发送验证码
+			verification() {
+				let obj = this;
+				if (this.account == '') {
+					this.$api.msg(obj.$t("login.a1"));
+					return;
+				}
+				if (this.account.length < 11) {
+					this.$api.msg(obj.$t("safe.b8"));
+					return;
+				}
+				// 判断是否在倒计时
+				if (obj.countDown > 0) {
+					return false;
+				} else {
+					obj.countDown = 60;
+					obj.time = setInterval(() => {
+						obj.countDown--;
+					}, 1000);
+					//调用验证码接口
+					verify({
+							phone: obj.account,
+							type: 'register'
+						})
+						.then(({
+							data
+						}) => {})
+						.catch(err => {
+							console.log(err);
+						});
+				}
+			},
+			login() {
+				//返回登录
+				uni.navigateTo({
+					url: '/pages/public/login'
+				});
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	page {
+		height: 100%;
+	}
+
+	.container {
+		width: 100%;
+		height: 100%;
+		background-size: 100%;
+		background-color: #000000;
+	}
+
+	.container_text {
+		width: 100%;
+		text-align: center;
+		.banner-img {
+			width: 144rpx;
+			margin-top: 100rpx;
+		}
+	}
+
+	.login_text {
+		margin: auto 10rpx;
+		position: relative;
+		padding: 100rpx 102rpx;
+		background-color: #000000;
+		border-radius: 20rpx;
+
+		.login_input {
+			border-bottom: 1px solid #f0f0f0;
+			margin-bottom: 65rpx;
+
+			.login_img image {
+				height: 35rpx;
+				width: 29rpx;
+				// padding-right: 20rpx;
+			}
+
+			.uni-input {
+				text-align: left;
+				width: 100%;
+				font-size: 28rpx !important;
+			}
+
+			.login_name {
+				color: #FFFFFF;
+				flex-grow: 1;
+				margin-left: 20rpx;
+			}
+		}
+
+		.other {
+			margin-top: 60rpx;
+
+			.fenge {
+				width: 30%;
+				height: 2rpx;
+				background-color: #eeeeee;
+			}
+
+			.qita {
+				font-size: 28rpx;
+				color: #999999;
+			}
+		}
+
+		// .weixin {
+		// 	width: 75rpx;
+		// 	height: 75rpx;
+		// 	margin: 25rpx auto;
+		// }
+
+		// .weixin image {
+		// 	width: 100%;
+		// 	height: 100%;
+		// }
+
+		// .weixin_text {
+		// 	text-align: center;
+		// 	font-size: 28rpx;
+		// 	color: #999999;
+		// }
+
+		.forget {
+			font-size: 28rpx;
+			width: 100%;
+			text-align: right;
+			color: #999999;
+		}
+		/* #ifdef H5 */
+		.loadapp {
+			border: 1px solid #feb041;
+			background-color: transparent;
+			color: #feb041;
+			width: 45%;
+		}
+		/* #endif */
+
+		.uni-button-green {
+			color: #ffffff;
+			background-color: #feb041;
+			margin: 40rpx 10rpx;
+			border-radius: 50rpx;
+		}
+
+		.uni-button-green-plain {
+			border: 1px solid #feb041;
+			margin: 40rpx 10rpx;
+			border-radius: 50rpx;
+			color: #feb041;
+			background-color: #000000;
+		}
+
+		.uni-button {
+			height: 85rpx;
+			line-height: 85rpx;
+		}
+	}
+
+	.loginTitle {
+		position: absolute;
+		top: 250rpx;
+		width: 100%;
+		text-align: center;
+		color: #c6a674;
+		font-size: 40rpx;
+	}
+
+	.forget {
+		width: 100rpx;
+		font-size: 24rpx;
+		color: #ffffff;
+		margin: 0px auto;
+		border-bottom: 1px solid #ffffff;
+	}
+
+	.width {
+		width: 325rpx !important;
+	}
+
+	.code {
+		color: #feb041;
+		font-size: 23rpx;
+		border-left: 1px solid #eeeeee;
+		width: 150rpx;
+		flex-shrink: 0;
+		text-align: center;
+	}
+
+	uni-button {
+		height: 80rpx !important;
+		line-height: 80rpx !important;
+	}
+</style>

+ 193 - 0
pages/public/wxLogin.vue

@@ -0,0 +1,193 @@
+<template>
+	<view class="content">
+		<!-- #ifndef H5 -->
+		<!-- <image class="bg-img" :src="baseURL+urlFile+'/img/img09.png'" mode=" scaleToFill"></image> -->
+		<view class="logo-img-box">
+			<image class="logo-img" src="https://hongmd.liuniu946.com/static/img/hmdlogo.png" mode=" aspectFit"></image>
+			<button class="userInfo" type="warn" @click="isclick?'':userInfoData()" :class="{'nocaction': isclick}">
+				<text class="iconfont iconweixin"></text>
+				<text>
+				微信授权登录
+				</text>
+			</button>
+		</view>
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+	import { getUserInfo } from '@/api/login.js';
+// #ifdef H5
+import { loginWinxin } from '@/utils/wxAuthorized';
+// #endif
+// #ifdef MP-WEIXIN
+import { loginWinxinMp } from '@/utils/wxMinProgram';
+import { wechatMpAuth } from '@/api/wx';
+// #endif
+import { mapMutations,mapState } from 'vuex';
+export default {
+	data() {
+		return {
+			userInfo:{},//授权用户信息
+			code:'',//授权code
+			isclick: false,//是否点击了
+		};
+	},
+	onLoad(option) {
+		this.loadData();
+	},
+	computed: {
+		// ...mapState(['baseURL','urlFile']) 
+	},
+	methods: {
+		// ...mapMutations(['login', 'setUserInfo']),
+		...mapMutations('user',['login', 'setUserInfo']),
+		loadData() {
+			let obj = this;
+			// #ifdef H5
+			loginWinxin();
+			// #endif
+			// #ifdef MP-WEIXIN
+			loginWinxinMp().then(() => {
+					wx.login({
+						success(e) {
+							console.log(e,'loginWinxinMp');
+							obj.code = e.code;
+						},
+						fill:function (e) {
+							console.log(e)
+						}
+					})
+			});
+			// #endif
+		},
+		// 用户确认授权
+		userInfoData(){
+			let that = this
+			if(that.isclick) {
+				return 
+			}
+			that.isclick = true
+			wx.getUserProfile({
+				desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
+				success: res => {
+					console.log(res,'that.userInfo+++++++++++++++++++')
+					that.userInfo = res;
+					uni.showLoading({
+						title: '授权中',
+						mask: true
+					});
+					that.loadMp();
+				},
+				fail: err => {
+					that.isclick = false
+					uni.showToast({
+						title: '您拒绝了请求,不能正常使用小程序',
+						icon: 'error',
+						duration: 2000
+					});
+					return;
+				}
+			});
+			// this.userInfo = e;
+			// console.log(e,'用户确认授权')
+			// this.loadMp()
+				
+		},
+		// #ifdef MP-WEIXIN
+		loadMp() {
+			let obj = this;
+			// 获取登录授权页数据
+			let user = obj.userInfo;
+			console.log(user)
+			// 获取推广人id
+			let spread_spid = uni.getStorageSync('spread') || '';
+			// #ifdef MP
+			let spread_code = uni.getStorageSync('spread_code') || '';
+			// #endif
+			
+			wechatMpAuth({
+				code: obj.code,
+				iv: user.iv,
+				encryptedData: user.encryptedData,
+				spread_spid: spread_spid,
+				// #ifdef MP
+				spread_code: spread_code,
+				// #endif
+			}).then(({ data }) => {
+				obj.wchatAuth(data);
+				console.log(data,'wechatMpAuth++++++++++++++++++++++++++')
+				
+			}).catch( err => {
+				// obj.loding = false;
+				// uni.hideLoading();
+			});
+		},
+		// #endif
+		wchatAuth(data) {
+			let obj = this;
+			// 保存token
+			uni.setStorageSync('token', data.token);
+			console.log(data.token,'token++++++++++++++')
+			// 获取用户基础信息
+			getUserInfo({}).then(e => {
+				console.log('userInfo+++++++++++',e)
+				obj.login();
+				uni.hideLoading();
+				// 保存返回用户数据
+				obj.setUserInfo(e.data);
+				let ur = uni.getStorageSync('present') || '/pages/index/index';
+				// 用于处理缓存bug
+				if (ur=='pages/shop/product') {
+					ur = '/pages/index/index'
+				}
+				uni.switchTab({
+					url: ur,
+					fail(e) {
+						uni.navigateTo({
+							url: ur,
+							fail(e) {
+								uni.navigateTo({
+									url: '/pages/index/index',
+								});
+							}
+						});
+					}
+				});
+			});
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+page,
+.content {
+	height: 100%;
+	background-color: #fff;
+}
+.bg-img,
+.logo-img-box {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+}
+.logo-img {
+	margin-top: 20vh;
+	margin-left: 176rpx;
+	width: 385rpx;
+	height: 394rpx;
+}
+.userInfo {
+	margin: 0 100rpx;
+	margin-top: 50rpx;
+	color: #FFFFFF;
+	border-radius: 99rpx;
+	background-color: $base-color !important;
+}
+.nocaction {
+	background-color: #999;
+}
+</style>

+ 135 - 0
pages/redirect/redirect.vue

@@ -0,0 +1,135 @@
+<template>
+	<view>
+	</view>
+</template>
+<script>
+	import {
+		getUserInfo
+	} from '@/api/user.js';
+	import {
+		mapMutations,
+		mapState
+	} from 'vuex';
+	// #ifdef H5
+	import {
+		wechatAuth
+	} from '@/api/wx';
+	// #endif
+	// #ifdef MP-WEIXIN
+	import {
+		wechatMpAuth
+	} from '@/api/wx';
+	// #endif
+	export default {
+		computed: {
+			...mapState(['urlFile'])
+		},
+		onLoad(option) {
+			let obj = this;
+			// 判断是否需要保存定向地址
+			// #ifdef H5
+			this.loadH5()
+			// #endif
+			// #ifdef MP-WEIXIN
+			this.loadMp(option)
+			// #endif
+		},
+		methods: {
+			...mapMutations('user', ['login', 'setUserInfo']),
+			// #ifdef H5
+			loadH5() {
+				let obj = this;
+				let url = window.location.href;
+				let code = url.match(/code=([0-9]|[a-z]|[A-Z])*/g)[0].replace('code=', '');
+				let spread = uni.getStorageSync('spread') || '';
+				wechatAuth({
+					code: code,
+					spread: spread,
+				}).then(({
+					data
+				}) => {
+					obj.wchatAuth(data);
+				}).catch((e) => {
+					uni.showModal({
+						title: '错误',
+						content: JSON.stringify(e),
+						showCancel: false,
+					});
+				});;
+			},
+			// #endif
+			// #ifdef MP-WEIXIN
+			loadMp(option) {
+				let obj = this;
+				// 获取登录授权页数据
+				let user = obj.$api.prePage().userInfo;
+				// #ifndef MP
+				// 获取推广人id
+				let spread_spid = uni.getStorageSync('spread') || '';
+				// #endif
+				// #ifdef MP
+				// 小程序推广人
+				let spread_code = uni.getStorageSync('spread_code') || '';
+				// #endif
+				wechatMpAuth({
+					code: option.code,
+					iv: user.target.iv,
+					encryptedData: user.target.encryptedData,
+					// #ifndef MP
+					spread_spid: spread_spid,
+					// #endif
+					// #ifdef MP
+					spread_code: spread_code
+					// #endif
+				}).then(({
+					data
+				}) => {
+					obj.wchatAuth(data);
+				}).catch((e) => {
+					uni.showModal({
+						title: '错误',
+						content: JSON.stringify(e),
+						showCancel: false,
+					});
+				});
+			},
+			// #endif
+			wchatAuth(data) {
+				let obj = this;
+				// 保存token
+				uni.setStorageSync('token', data.token);
+				// 获取用户基础信息
+				getUserInfo({}).then(e => {
+					obj.login();
+					// 保存返回用户数据
+					obj.setUserInfo(e.data);
+					let ur = uni.getStorageSync('present') || '/pages/index/index';
+					// 用于处理缓存bug
+					if (ur == 'pages/product/product') {
+						ur = '/pages/index/index'
+					}
+					uni.switchTab({
+						url: ur,
+						fail(e) {
+							uni.navigateTo({
+								url: ur,
+								fail(e) {
+									uni.navigateTo({
+										url: '/pages/index/index',
+									});
+								}
+							});
+						}
+					});
+				}).catch((e) => {
+					uni.showModal({
+						title: '错误',
+						content: JSON.stringify(e),
+						showCancel: false,
+					});
+				});;
+			}
+		}
+	};
+</script>
+<style></style>

+ 299 - 0
pages/user/favorites.vue

@@ -0,0 +1,299 @@
+<template>
+	<view class="container">
+		<swiper
+			class="posters-box"
+			:autoplay="false"
+			:circular="false"
+			:interval="3000"
+			:duration="500"
+			@change="bindchange"
+			previous-margin="40px"
+			next-margin="40px">
+			<block
+				v-for="(item, index) in shareList"
+				:key="index">
+				<swiper-item>
+					<!-- #ifndef MP -->
+					<image
+						class="slide-image"
+						:class="swiperIndex == index ? 'active' : 'quiet'"
+						mode="aspectFill"
+						:src="item.wap_poster"></image>
+					<!-- #endif -->
+
+					<!-- #ifdef MP -->
+					<image
+						class="slide-image"
+						:class="swiperIndex == index ? 'active' : 'quiet'"
+						mode="aspectFill"
+						:src="item.poster"></image>
+					<!-- #endif -->
+				</swiper-item>
+			</block>
+		</swiper>
+		<!-- #ifndef MP -->
+		<div class="preserve">
+			<div class="line"></div>
+			<div class="tip">{{$t('huiyuan.b1')}}</div>
+			<div class="line"></div>
+		</div>
+		<!-- #endif -->
+
+		<!-- #ifdef MP -->
+		<view
+			class="keep"
+			@click="savePosterPath"
+			>{{$t('huiyuan.b2')}}</view
+		>
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+	import { spreadBanner } from "@/api/user.js";
+	import { mapState } from "vuex";
+	export default {
+		// #ifdef MP
+		onShareAppMessage: function (res) {
+			// 保存邀请人
+			let path = "/pages/index/index?" + "spread=" + this.userInfo.uid;
+			let data = {
+				path: path,
+				imageUrl: this.poster,
+				title: this.userInfo.nickname +  this.$t("huiyuan.b3"),
+			};
+			return data;
+		},
+		// #endif
+		data() {
+			return {
+				shareList: [],
+				swiperIndex: 0,
+				poster: "", // 当前海报
+			};
+		},
+		onLoad(option) {
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.b2"),
+			});
+			this.loadData();
+		},
+		computed: {
+			...mapState("user", ["userInfo"]),
+		},
+		methods: {
+			bindchange(e) {
+				let shareList = this.shareList;
+				this.swiperIndex = e.detail.current;
+				// #ifdef MP
+				this.poster = shareList[this.swiperIndex].poster;
+				// #endif
+
+				console.log(this.poster);
+			},
+
+			// 保存海报
+			savePosterPath: function () {
+				let that = this;
+				if (that.poster == "") {
+					that.poster = that.shareList[0].poster;
+				}
+				uni.downloadFile({
+					url: that.poster,
+					success(resFile) {
+						if (resFile.statusCode === 200) {
+							uni.getSetting({
+								success(res) {
+									if (
+										!res.authSetting[
+											"scope.writePhotosAlbum"
+										]
+									) {
+										uni.authorize({
+											scope: "scope.writePhotosAlbum",
+											success() {
+												uni.saveImageToPhotosAlbum({
+													filePath:
+														resFile.tempFilePath,
+													success: function (res) {
+														return that.$api.msg(
+															 this.$t("huiyuan.b4")
+														);
+													},
+													fail: function (res) {
+														return that.$api.msg(
+															res.errMsg
+														);
+													},
+													complete: function (res) {},
+												});
+											},
+											fail() {
+												uni.showModal({
+													title: this.$t("huiyuan.b5"),
+													content:
+														 this.$t("huiyuan.b6"),
+													success(res) {
+														if (res.confirm) {
+															uni.openSetting({
+																success:
+																	function (
+																		res
+																	) {
+																		console.log(
+																			res.authSetting
+																		);
+																	},
+															});
+														} else if (res.cancel) {
+															return that.$api.msg(
+																 this.$t("huiyuan.b7")
+															);
+														}
+													},
+												});
+											},
+										});
+									} else {
+										uni.saveImageToPhotosAlbum({
+											filePath: resFile.tempFilePath,
+											success: function (res) {
+												return that.$api.msg(
+													 this.$t("huiyuan.b8")
+												);
+											},
+											fail: function (res) {
+												return that.$api.msg(
+													res.errMsg
+												);
+											},
+											complete: function (res) {},
+										});
+									}
+								},
+								fail(res) {},
+							});
+						} else {
+							return that.$api.msg(resFile.errMsg);
+						}
+					},
+					fail(res) {
+						return that.$api.msg(res.errMsg);
+					},
+				});
+			},
+
+			// #ifdef MP-WEIXIN
+			// 保存画图图片到本地
+			seav(url) {
+				uni.showLoading({
+					title:  this.$t("huiyuan.b9"),
+					mask: true,
+				});
+				uni.saveImageToPhotosAlbum({
+					filePath: this.poster,
+					complete(result) {
+						uni.hideLoading();
+						console.log(result);
+						uni.showToast({
+							title:  this.$t("huiyuan.b0"),
+							duration: 2000,
+							icon: "none",
+						});
+					},
+				});
+			},
+			// #endif
+
+			// 获取海报
+			loadData() {
+				let obj = this;
+				uni.showLoading({
+					title: "获取中",
+					mask: true,
+				});
+				spreadBanner({
+					// #ifdef H5
+					type: 2,
+					// #endif
+					// #ifdef MP
+					type: 1,
+					// #endif
+				})
+					.then(res => {
+						uni.hideLoading();
+						obj.shareList = res.data;
+						console.log("obj.shareList", obj.shareList);
+					})
+					.catch(err => {
+						uni.hideLoading();
+					});
+			},
+		},
+	};
+</script>
+
+<style lang="scss">
+	page {
+		background: #a3a3a3;
+		height: 100%;
+	}
+
+	.container {
+		width: 100%;
+
+		.posters-box {
+			width: 100%;
+			height: 1000rpx;
+			margin-top: 40rpx;
+
+			.slide-image {
+				width: 100%;
+				height: 100%;
+				border-radius: 15rpx;
+			}
+		}
+
+		.posters-box .slide-image.active {
+			transform: none;
+			transition: all 0.2s ease-in 0s;
+		}
+
+		.posters-box .slide-image.quiet {
+			transform: scale(0.8333333);
+			transition: all 0.2s ease-in 0s;
+		}
+
+		.keep {
+			font-size: 30rpx;
+			background: $base-color;
+			color: #fff;
+			width: 600rpx;
+			height: 80rpx;
+			border-radius: 50rpx;
+			text-align: center;
+			line-height: 80rpx;
+			margin: 38rpx auto;
+		}
+	}
+
+	.preserve {
+		color: #fff;
+		text-align: center;
+		margin-top: 38rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+
+		.line {
+			width: 100rpx;
+			height: 1px;
+			background-color: #fff;
+		}
+
+		.tip {
+			margin: 0 20rpx;
+			font-size: 28rpx;
+		}
+	}
+</style>

+ 456 - 0
pages/user/money/recharge.vue

@@ -0,0 +1,456 @@
+<template>
+	<view class="content">
+		<view class="main-jg"></view>
+		<view class="add-wrapper">
+			<view class="add-box">
+				<view class="add-log">$</view>
+				<input type="text" v-model="money" :placeholder="$t('recharge.请输入充值金额')" placeholder-class="place"
+					@keyup="clearNoNum()" />
+			</view>
+			<view class="jg" style="height: 1px; background-color: #E6E6E6;"></view>
+			<view class="add-tags">
+				<view class="tag" v-for="(item, index) in addTags" :key="item" @click="tagClick(index)"
+					:class="{ action: currentIndex === index && money == addTags[index] }">
+					<text>{{ item }}</text>
+					USDT
+				</view>
+			</view>
+		</view>
+		<view class="main-jg"></view>
+		<button class="add-btn up" :class="{ 'active-bg': payLoding }"
+			@click="!payLoding ? confirm() : ''">{{$t('recharge.立即充值')}}</button>
+
+	</view>
+</template>
+
+<script>
+	import {
+		getMoneyStyle
+	} from '@/utils/rocessor.js';
+
+	import {
+		gamecharge,
+		gamechargePost
+	} from '@/api/game.js';
+
+	import {
+		mapState
+	} from 'vuex';
+	import detectEthereumProvider from '@metamask/detect-provider'
+	export default {
+		filters: {
+			getMoneyStyle
+		},
+		data() {
+			return {
+				money: '', //充值金额
+				payLoding: false, //是否加载中
+				addTags: [300, 200, 150, 100, 50],
+				currentIndex: '',
+			};
+		},
+		computed: {
+			// #ifdef H5
+			...mapState(['weichatObj']),
+			// #endif
+			...mapState('user', ['userInfo'])
+		},
+		onLoad() {
+			uni.setNavigationBarTitle({
+				title: this.$t('user.a7')
+			});
+		},
+		methods: {
+			// 跳转
+			navTo(url) {
+				uni.navigateTo({
+					url: url
+				});
+			},
+			// 切换选中对象
+			tabRadio(e) {
+				console.log(e)
+				this.type = e;
+			},
+			// 提交
+			async confirm() {
+				let obj = this;
+				if (this.money == 0) {
+					return this.$api.msg(this.$t('recharge.请输入充值金额'));
+				}
+
+				obj.payLoding = true;
+				uni.showLoading({
+					title: 'loding...',
+					mask:true
+				});
+				try {
+					const res = await gamecharge({
+						token: "USDT",
+						num: this.money,
+					})
+					const txHash = await ethereum.request({
+						method: 'eth_sendTransaction',
+						params: [{
+							from: obj.userInfo.account, // The user's active address.
+							to: res.data.to,
+							value: 0,
+							data: res.data.data.data,
+						}]
+					})
+					const PKR_RECHARGE = "PKR_RECHARGE" + (new Date()).getTime()
+					const sign = await ethereum.request({
+						"method": "personal_sign",
+						"params": [
+							PKR_RECHARGE,
+							obj.userInfo.account
+						]
+					})
+					const req = await gamechargePost({
+						num: obj.money,
+						token: "USDT",
+						transactionHash: txHash,
+						msg: PKR_RECHARGE,
+						sign:sign
+					});
+					uni.showToast({
+						title:this.$t('userinfo.u24')
+					})
+					obj.payLoding = false;
+				} catch (e) {
+					obj.payLoding = false;
+					uni.showToast({
+						title:this.$t('recharge.申请失败'),
+						icon:'error'
+					})
+				}
+			},
+			//获取订单列表
+			loadData(source) {
+				console.log(source);
+				//这里是将订单挂载到tab列表下
+				let index = this.tabCurrentIndex;
+				let navItem = this.navList[index];
+				let state = navItem.state;
+				if (source === 'tabChange' && navItem.loaded === true) {
+					//tab切换只有第一次需要加载数据
+					return;
+				}
+				if (navItem.loadingType === 'loading') {
+					//防止重复加载
+					return;
+				}
+				navItem.loadingType = 'loading';
+				setTimeout(() => {
+					let orderList = [];
+					orderList.forEach(item => {
+						navItem.orderList.push(item);
+					});
+					//loaded新字段用于表示数据加载完毕,如果为空可以显示空白页
+					this.$set(navItem, 'loaded', true);
+					//判断是否还有数据, 有改为 more, 没有改为noMore
+					navItem.loadingType = 'more';
+				}, 600);
+			},
+			tagClick(index) {
+				this.currentIndex = index;
+				this.money = this.addTags[index];
+			},
+			clearNoNum() {
+				this.money = this.money.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3');
+				switch (this.money) {
+					case '300':
+						this.currentIndex = 0;
+						break;
+					case '200':
+						this.currentIndex = 1;
+						break;
+					case '150':
+						this.currentIndex = 2;
+						break;
+					case '100':
+						this.currentIndex = 3;
+						break;
+					case '50':
+						this.currentIndex = 4;
+						break;
+				}
+			},
+			btnClick() {
+				this.isSect = !this.isSect
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	page {
+		height: 100%;
+		background-color: #fff;
+	}
+
+	.add-btn {
+
+		&.modified {
+			color: $base-color;
+		}
+
+		&.up {
+
+			background: linear-gradient(-90deg, #FAC545, #FFE000);
+			color: #6B4216;
+		}
+
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		width: 604rpx;
+		height: 90rpx;
+		margin: 0 auto;
+		margin-top: 30rpx;
+		font-size: $font-lg;
+		border-radius: 10rpx;
+
+	}
+
+	.row-box {
+		margin-top: 30rpx;
+		padding: 20rpx 30rpx;
+		background: #fff;
+
+		.title {
+			font-size: $font-base + 2rpx;
+			color: $font-color-dark;
+		}
+
+		.row {
+			display: flex;
+			align-items: center;
+			position: relative;
+			height: 80rpx;
+
+			.tit {
+				flex-shrink: 0;
+				width: 40rpx;
+				font-size: 30rpx;
+				color: $font-color-dark;
+			}
+
+			.input {
+				flex: 1;
+				font-size: 30rpx;
+				color: $font-color-dark;
+			}
+
+			.iconlocation {
+				font-size: 36rpx;
+				color: $font-color-light;
+			}
+
+			.buttom {
+				color: $font-color;
+				font-size: $font-base;
+			}
+		}
+	}
+
+	.list {
+		padding-left: 30rpx;
+		margin-top: 30rpx;
+		background-color: #ffffff;
+
+		.box {
+			display: flex;
+			align-items: center;
+			width: 100%;
+			height: 120rpx;
+			border-bottom: 1px solid $border-color-light;
+
+			.icon {
+				font-size: 48rpx;
+				padding-right: 20rpx;
+			}
+
+			.iconweixin1 {
+				color: #18bf16;
+			}
+
+			.iconzhifubao {
+				color: #08aaec;
+			}
+
+			.title-box {
+				flex-grow: 1;
+				text-align: left;
+
+				.title {
+					font-size: $font-base + 2rpx;
+					color: $font-color-base;
+				}
+
+				.node {
+					font-size: $font-sm;
+					color: $font-color-light;
+				}
+			}
+		}
+	}
+
+	/deep/ .uni-radio-input {
+		width: 45rpx;
+		height: 45rpx;
+	}
+
+	.active-bg {
+		background-color: $color-gray !important;
+	}
+
+	.now {
+		width: 100%;
+		height: 86rpx;
+		padding: 0 26rpx 0 47rpx;
+		display: flex;
+		justify-content: space-between;
+		line-height: 86rpx;
+		background-color: #fff;
+		// margin-bottom: 21rpx;
+
+		view {
+			font-size: 28rpx;
+			font-weight: 500;
+			color: #333333;
+		}
+
+		.now-money {
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #FF4C4C;
+		}
+	}
+
+	.add-wrapper {
+		width: 750rpx;
+		height: 338rpx;
+		padding-left: 30rpx;
+		background: #ffffff;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+
+		// margin-bottom: 22rpx;
+		.add-box {
+			width: 100%;
+			height: 103rpx;
+			display: flex;
+			flex-direction: row;
+			justify-content: space-between;
+			padding: 0 39rpx 0 10rpx;
+			align-items: center;
+
+			.add-log {
+				font-size: 37rpx;
+				font-weight: bold;
+			}
+
+			input {
+				height: 30rpx;
+				font-size: 32rpx;
+				font-weight: 500;
+				color: #000;
+				line-height: 40px;
+				text-align: right;
+				flex-grow: 1;
+
+				.place {
+					color: #bfbfbf;
+				}
+			}
+		}
+
+		.jg {
+			width: 100%;
+		}
+
+		.add-tags {
+			height: 234rpx;
+			padding-top: 47rpx;
+			padding-bottom: 17rpx;
+			display: flex;
+			flex-direction: row;
+			flex-wrap: wrap;
+
+			// justify-content: space-between;
+			.tag {
+				width: 210rpx;
+				height: 70rpx;
+				background-color: #f0f0f0;
+				border-radius: 4rpx;
+				margin: 0 30rpx 30rpx 0;
+				text-align: center;
+				line-height: 70rpx;
+				font-size: 22rpx;
+
+				text {
+					font-size: 32rpx;
+					font-weight: 500;
+				}
+			}
+
+			.action {
+				color: #6B4216;
+				background: linear-gradient(-90deg, #FAC545, #FFE000);
+			}
+		}
+	}
+
+	.btn-wrapper {
+		padding: 49rpx 32rpx 0 40rpx;
+		height: 183rpx;
+		display: flex;
+		justify-content: space-between;
+		background-color: #fff;
+
+		.iconweixin1 {
+			color: #18bf16;
+			font-size: 48rpx;
+			display: flex;
+
+			view {
+				// display: inline-block;
+				height: 48rpx;
+				text-align: 48rpx;
+				padding-left: 20rpx;
+				// padding-top: 10rpx;
+				color: #000000;
+				font-size: 30rpx;
+			}
+		}
+
+		.btn {
+			width: 36rpx;
+			height: 36rpx;
+			border: 4rpx #333 solid;
+			border-radius: 8rpx 8rpx;
+
+			image {
+				// display: none;
+				width: 100%;
+				height: 100%;
+			}
+
+			.action {
+				display: none;
+			}
+		}
+
+		.actiont {
+			border: none;
+		}
+	}
+
+	.main-jg {
+		width: 100%;
+		height: 21rpx;
+		background-color: #f8f6f6;
+	}
+</style>

+ 166 - 0
pages/user/money/recharge备份.vue

@@ -0,0 +1,166 @@
+<template>
+	<view class="all padding-c-30 padding-v-30">
+		<view class="top">
+			<view class="topO"> {{$t('userinfo.u4')}} </view>
+			<view class="topT flex-start padding-t-30">
+				<view class="tt">USDT-TRC20</view>
+			</view>
+			<view class="topS flex-start">
+				<view class="S">{{$t('userinfo.u1')}}</view>
+				<view class="SS clamp padding-c-10">{{ address }}</view>
+				<image class="SSS" src="/static/icon/cz.png" mode="" @click="copy(address)">
+				</image>
+			</view>
+			<!-- 根据地址生成二维码 -->
+			<view class="qr flex-center">
+				<uqrcode h5DownloadName='myqrcode' ref="qrcode" canvas-id="qrcode" :value="address" size="240" sizeUnit='rpx'>
+				</uqrcode>
+			</view>
+
+			<view class="last flex">
+				<view class="le" @click="savePic">
+					<view class="lef">{{$t('userinfo.u2')}}</view>
+				</view>
+				<view class="le" style="margin-left: 30rpx;">
+					<view class="lef" @click="copy(address)">{{$t('userinfo.u3')}}</view>
+				</view>
+			</view>
+		</view>
+		<view class="buttom">
+			<view class="but">
+				{{$t('userinfo.u5')}}
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		qianBao
+	} from "@/api/wallet.js"
+	export default {
+		data() {
+			return {
+				address: '',
+				qr:''
+			};
+		},
+		mounted() {},
+		onReady() {},
+		onLoad() {
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.a3"),
+			});
+			this.qianBao()
+		},
+		methods: {
+			// 二维码地址
+			async qianBao() {
+				const res = await qianBao()
+				this.address = res.data.back.USDT.money.address;
+			},
+			// 复制地址
+			copy(value) {
+				uni.setClipboardData({
+					data: value,
+					success: function() {
+						//调用方法成功
+						console.log("success");
+					},
+				});
+			},
+			savePic(Url) {
+				this.$refs.qrcode.save({});
+			},
+		},
+	};
+</script>
+
+<style lang="scss">
+	.all {
+		line-height: 1;
+		color: #ffffff;
+	}
+
+	.top {
+		padding: 40rpx 30rpx;
+		background: #191a1f;
+		border-radius: 20rpx;
+
+		.topO {
+			font-size: $font-lg;
+			font-weight: bold;
+		}
+
+		.topT {
+			.tt {
+				padding: 20rpx 24rpx;
+				border-radius: 10rpx;
+				border: 2px solid #ddba82;
+				font-size: 26rpx;
+				font-weight: bold;
+				color: #feb041;
+			}
+		}
+
+		.topS {
+			padding-top: 30rpx;
+
+			.S {
+				font-size: $font-lg;
+				font-weight: bold;
+				flex-shrink: 0;
+			}
+
+			.SS {
+				font-size: $font-sm;
+				flex-grow: 1;
+			}
+
+			.SSS {
+				flex-shrink: 0;
+				width: 29rpx;
+				height: 29rpx;
+			}
+		}
+	}
+
+	.qr {
+		margin: 0 auto;
+		margin-top: 34rpx;
+		width: 275rpx;
+		height: 275rpx;
+		background-color: #fff;
+	}
+
+	.last {
+		margin-top: 50rpx;
+		padding: 0 30rpx;
+
+		.le {
+			padding: 20rpx 0;
+			width: 250rpx;
+			border: 2px solid #DDBA82;
+			text-align: center;
+			border-radius: 10rpx;
+
+			.lef {
+				font-size: 26rpx;
+				font-weight: bold;
+				color: #FEB041;
+			}
+		}
+	}
+
+	.buttom {
+		background: #191a1f;
+		border-radius: 20rpx;
+		margin-top: 30rpx;
+		padding: 30rpx;
+		.but {
+			font-size: 26rpx;
+			font-weight: 500;
+			line-height: 45rpx;
+		}
+	}
+</style>

+ 318 - 0
pages/user/money/team.vue

@@ -0,0 +1,318 @@
+<template>
+	<view class="content">
+		<view class="type flex-start">
+			<view class="item" :class="{action:type=='USDT'}" @click="onchangeType('USDT')">
+				USDT
+			</view>
+			<view class="item" :class="{action:type=='PKR'}" @click="onchangeType('PKR')">
+				PKR
+			</view>
+		</view>
+		<view class="content-money flex">
+			<view class="money-box">
+				<view class="margin-b-20">{{$t('money.a2')}}</view>
+				<view class="money" v-if="type=='PKR'">{{userInfo.pkr}}</view>
+				<view class="money" v-if="type=='USDT'">{{userInfo.usdt}}</view>
+			</view>
+			<!-- 数据代办 -->
+			<view class="box">
+				<view class="moneybtn-box">
+					<view class="money-btn"></view>
+					<view class="money-btn" @click="navto('/pages/user/money/recharge')">{{$t('money.a3')}}</view>
+				</view>
+				<view class="moneybtn-box margin-t-10">
+					<view class="money-btn"></view>
+					<view class="money-btn" @click="navto('/pages/user/money/withdrawal')">{{$t('money.a4')}}</view>
+				</view>
+			</view>
+		</view>
+
+		<view class="info-box flex">
+			<view class="info-item">
+				<view class="info-font">{{$t('money.a5')}}</view>
+				<view class="info-num">{{userInfo.sum_income|| '0'}}</view>
+			</view>
+			<view class="shu"></view>
+			<view class="info-item">
+				<view class="info-font">{{$t('money.a6')}}</view>
+				<view class="info-num">{{userInfo.sum_expend  || '0'}}</view>
+			</view>
+		</view>
+
+		<scroll-view :style="{height:height}" scroll-y="true" class="padding-b-20 padding-c-30 list-scroll-content"
+			@scrolltolower="loadData">
+			<!-- 订单列表 -->
+			<view class="list flex padding-v-30" v-for="(item, index) in list" :key="index">
+				<view>
+					<view class="tit padding-b-20">{{item.mark}}</view>
+					<view class="tim">{{item.add_time}}</view>
+				</view>
+				<view class="boxT">
+					<text v-if="item.pm==1">+</text>
+					<text v-if="item.pm==0">-</text>
+					<text class="mon">{{item.number*1}}</text>
+				</view>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import {
+		getMoneyLog
+	} from "@/api/wallet.js"
+	import {
+		gameWallet,
+	} from "@/api/game.js";
+	import {
+		getMoneyStyle
+	} from '@/utils/rocessor.js';
+	import empty from '@/components/empty';
+	export default {
+		filters: {
+			getMoneyStyle
+		},
+		components: {
+			empty,
+		},
+		data() {
+			return {
+				userInfo: {
+					sum_expend:'',
+					sum_income:'',
+					pkr:'',
+					usdt:''
+				},
+				userWallet: '', //余额
+				height: '',
+				loaded: false,
+				list: [],
+				money: '',
+				page: 1,
+				limit: 10,
+				loadingType: 'more',
+				type:"USDT"
+			};
+		},
+		onLoad(options) {},
+		onReady(res) {
+			var _this = this;
+			uni.getSystemInfo({
+				success: resu => {
+					const query = uni.createSelectorQuery();
+					query.select('.list-scroll-content').boundingClientRect();
+					query.exec(function(res) {
+						console.log(res[0].top);
+						console.log(resu.windowHeight);
+						_this.height = resu.windowHeight - res[0].top + 'px';
+					});
+				},
+				fail: res => {}
+			});
+		},
+		onShow() {
+			// this.getUserInfo();
+			this.loadData();
+			this.getUserWallet();
+		},
+		methods: {
+			onchangeType(type){
+				this.type = type;
+				this.page = 1;
+				this.loadingType = 'more';
+				this.loaded = false;
+				this.list = [];
+				this.loadData();
+			},
+			// 获取用户余额信息
+			getUserWallet() {
+				gameWallet().then((res) => {
+					this.userInfo.pkr = +res.data.back.PKR.money.money
+					this.userInfo.usdt = +res.data.back.USDT.money.money
+				})
+			},
+			// getUserInfo() {
+			// 	getUserInfo({}).then(({
+			// 		data
+			// 	}) => {
+			// 		this.userInfo = data
+					
+			// 	});
+			// },
+			toBack() {
+				uni.switchTab({
+					url: '/pages/index/user'
+				});
+			},
+			// 页面跳转
+			navto(e) {
+				uni.navigateTo({
+					url: e
+				});
+			},
+
+			//获取收入支出信息
+			async loadData(source) {
+				let navItem = this;
+				if (navItem.loaded === true || navItem.loadingType === 'loading') {
+					//tab切换只有第一次需要加载数据
+					return;
+				}
+				// 修改当前对象状态为加载中
+				navItem.loadingType = 'loading';
+				getMoneyLog({
+						page: navItem.page,
+						limit: navItem.limit
+					},navItem.type)
+					.then(({
+						data
+					}) => {
+						navItem.userInfo.sum_expend = data.sum_expend;
+						navItem.userInfo.sum_expend = data.sum_expend;
+						navItem.list = navItem.list.concat(data.list);
+						navItem.page++;
+						//判断是否还有数据, 有改为more, 没有改为noMore
+						if (navItem.limit == data.list.length) {
+							navItem.loadingType = 'more';
+							return;
+						} else {
+							navItem.loadingType = 'noMore';
+						}
+						uni.hideLoading();
+						this.$set(navItem, 'loaded', true);
+					})
+					.catch(e => {
+						console.log(e);
+					});
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	.content {
+		line-height: 1;
+	}
+
+	.content-money {
+		position: relative;
+		padding: 60rpx 30rpx;
+		height: 250rpx;
+		margin-top: -20rpx;
+		.box {
+			position: absolute;
+			right: 0;
+			top: 50rpx;
+			font-size: 30rpx;
+			font-weight: bold;
+			color: #ffffff;
+
+			.moneybtn-box {
+				padding: 14rpx 40rpx;
+				border: 2px solid #FFFFFF;
+				border-bottom-left-radius: 100rpx;
+				border-top-left-radius: 100rpx;
+				border-right: none;
+			}
+		}
+
+		.money-box {
+			position: relative;
+			z-index: 2;
+			color: #ffffff;
+			text-align: left;
+
+			.money {
+				font-weight: bold;
+				font-size: 72rpx;
+				color: #fdb242;
+			}
+		}
+	}
+
+	.info-box {
+		background: #1d1d22;
+		border-radius: 20rpx;
+		margin: 0 30rpx;
+		padding: 30rpx;
+
+		.info-item {
+			width: 50%;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			line-height: 1;
+
+			.info-font {
+				font-size: 30rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				text-align: center;
+				color: #e2e2e2;
+			}
+
+			.info-num {
+				margin-top: 30rpx;
+				font-size: 30rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #ffffff;
+			}
+		}
+
+		.shu {
+			width: 2rpx;
+			height: 74rpx;
+			background: #ffffff;
+		}
+	}
+
+
+
+
+
+	.content {
+		height: 100%;
+
+		.empty-content {
+			background-color: #ffffff;
+		}
+
+	}
+
+	// border-bottom: 1px solid #ffffff;
+
+	.list {
+		border-bottom: 1px solid $font-color-light;
+		.tit {
+			font-size: $font-base;
+			font-weight: 500;
+			color: #FFFFFF;
+		}
+
+		.tim {
+			font-size: 22rpx;
+			font-weight: 400;
+			color: #999999;
+		}
+
+		.boxT {
+			font-weight: bold;
+			font-size: 30rpx;
+			color: #FDB242;
+		}
+	}
+	.type{
+		padding: 30rpx 30rpx 0 30rpx;
+		font-size: 38rpx;
+		color: #FFF;
+		.item{
+			padding: 20rpx 20rpx;
+			margin-right: 10rpx;
+			&.action{
+				color: #FDB242;
+				border-bottom: 1px solid #FDB242;
+			}
+		}
+	}
+</style>

+ 259 - 0
pages/user/money/withdrawal.vue

@@ -0,0 +1,259 @@
+<template>
+	<view class="all">
+		<view class="top">
+			<view class="topO">
+				{{$t('userinfo.u6')}}
+			</view>
+			<view class="topT flex-start padding-b-30">
+				<view class="TT">USDT</view>
+				<view class="TT noaction" @click="openPkr">PKR</view>
+			</view>
+			<view class="topO">
+				{{$t('userinfo.u7')}}
+			</view>
+			<view class="topF margin-b-30">
+				<input class="FF" type="text" :placeholder="$t('userinfo.u17')" v-model="address"
+					placeholder-class="placeholder-input" />
+			</view>
+			<view class="topO ">
+				{{$t('userinfo.u8')}} <text class="font-color-gray font-size-sm">({{$t('userinfo.u19')}}:{{userWallet}})</text>
+			</view>
+			<view class="topF flex margin-b-30">
+				<input class="FF" type="number" v-model="withdrawal" :placeholder="$t('userinfo.u18')"
+					placeholder-class="placeholder-input" />
+				<view class="btn" @click="withdrawal=userWallet">USDT {{$t('userinfo.u20')}}</view>
+			</view>
+			<view class="topO ">
+				{{$t('userinfo.u21')}} ({{num}}%)
+			</view>
+			<view class="topF flex">
+				<text v-if="type==1">{{charge}}</text>
+				<text v-else>{{num}}</text>
+			</view>
+		</view>
+		<view class="center margin-t-30">
+			<view class="tx">{{$t('userinfo.u9')}}</view>
+			<view class="buzhou margin-t-20">
+				<view class="">1.{{$t('userinfo.u10')}} </view>
+				<view class="">① {{$t('userinfo.u11')}}</view>
+				<view class="">② {{$t('userinfo.u12')}} </view>
+				<view class="">2.{{$t('userinfo.u13')}}</view>
+				<view class="">3.{{$t('userinfo.u14')}}</view>
+				<view class="">4.{{$t('userinfo.u15')}}</view>
+			</view>
+		</view>
+		<view class="last margin-t-30" @click="openPayPassword">
+			<view class="la" :class="{action:loding}">{{$t('userinfo.u16')}}</view>
+		</view>
+		<uni-popup type="bottom" ref="popup">
+			<inputPassword @commit='KeyInfo'></inputPassword>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import {
+		gameWallet
+	} from "@/api/game.js";
+	import {
+		extractCash
+	} from "@/api/wallet.js";
+	import inputPassword from "@/components/input-password/input-password.vue";
+	export default {
+		components: {
+			inputPassword
+		},
+		data() {
+			return {
+				address: '', //提现地址
+				withdrawal: '', //提现金额
+				userWallet: '',
+				loding: false,
+				password: '',
+				// 手续费信息
+				type: 0,
+				num: 0//手续费百分比
+			};
+		},
+		computed: {
+			charge() {
+				return Number( (this.withdrawal*this.num/100).toFixed(8))
+			}
+		},
+		onLoad() {
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.a8"),
+			});
+			this.gameWallet();
+		},
+		methods: {
+			openPkr(){
+				uni.showToast({
+					// title: '余额不足!',
+					title: this.$t("withdrawal.暂未开放"),
+					icon: 'error'
+				});
+			},
+			// 支付弹窗
+			openPayPassword() {
+				if (this.userWallet < this.withdrawal) {
+					uni.showToast({
+						// title: '余额不足!',
+						title: this.$t("userinfo.u22"),
+						icon: 'error'
+					});
+					return
+				};
+				this.$refs.popup.open();
+			},
+			// 关闭支付弹窗
+			colsePayPassword() {
+				this.$refs.popup.close();
+			},
+			// 密码输入完成
+			KeyInfo(val) {
+				this.password = val;
+				this.colsePayPassword();
+				this.submit();
+			},
+			// 获取用户信息
+			gameWallet() {
+				const that = this;
+				gameWallet().then((res) => {
+					that.userWallet = +res.data.back.USDT.money.money;
+					that.type = +res.data.back.USDT.cash_commission_count_type;
+					that.num = +res.data.back.USDT.cash_commission_ratio;
+				})
+			},
+			// 提交
+			submit() {
+				const that = this;
+				uni.showLoading({
+					title: this.$t("userinfo.u23"),
+					mask: true
+				});
+				that.loding = true;
+				extractCash({
+					money: that.withdrawal,
+					money_type: "USDT",
+					address: that.address,
+					trade_password: that.password,
+				}).then((res) => {
+					that.loding = false;
+					uni.hideLoading()
+					uni.showToast({
+						title: this.$t("userinfo.u24")
+					});
+					this.address = '';
+					this.withdrawal = ''; //提现金额
+					this.password = '';
+				}).catch((res) => {
+					uni.showToast({
+						title: this.$t("userinfo.u25"),
+						icon: 'error'
+					});
+					that.loding = false;
+					uni.hideLoading()
+				})
+
+
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.all {
+		color: #FFFFFF;
+		padding: 0 30rpx;
+		line-height: 1;
+		padding-bottom: 150rpx;
+	}
+
+	.placeholder-input {
+		color: $font-color-light;
+	}
+
+	.top {
+		background: #191A1F;
+		border-radius: 20rpx;
+		padding: 40rpx 30rpx;
+		
+		.topO {
+			font-size: $font-lg;
+			padding-bottom: 30rpx;
+		}
+
+		.topT {
+			.TT {
+				border: 2px solid #DDBA82;
+				border-radius: 10rpx;
+				font-size: 26rpx;
+				color: #FEB041;
+				padding: 20rpx 24rpx;
+				&.noaction{
+					margin-left: 20rpx;
+					border-color: #999999;
+					color: #999999;
+				}
+			}
+
+		}
+
+		.topF {
+			background-color: rgba(254, 176, 65, 0.09);
+			border-radius: 20rpx;
+			padding: 20rpx 30rpx;
+
+			.FF {
+				font-size: $font-base;
+				flex-grow: 1;
+			}
+
+			.btn {
+				font-size: $font-base;
+			}
+		}
+	}
+
+	.center {
+		background: #191A1F;
+		border-radius: 20rpx;
+		font-weight: 500;
+		padding: 30rpx;
+
+		.tx {
+			font-size: 29rpx;
+			line-height: 30rpx;
+		}
+
+		.buzhou {
+			font-size: 24rpx;
+			color: #999999;
+			line-height: 40rpx;
+		}
+	}
+
+
+	.last {
+		background: #feb041;
+		border-radius: 10rpx;
+		overflow: hidden;
+		position: fixed;
+		bottom: 30rpx;
+		left: 30rpx;
+		right:30rpx;
+		.la {
+			font-size: $font-lg;
+			font-weight: bold;
+			color: #040404;
+			text-align: center;
+			padding: 30rpx;
+
+			&.action {
+				color: #FFF;
+				background-color: $font-color-light;
+			}
+		}
+	}
+</style>

+ 162 - 0
pages/user/set/password.vue

@@ -0,0 +1,162 @@
+<template>
+	<view class="container">
+		<view class="row b-b">
+			<text class="tit">{{$t('set.a3')}}</text>
+			<input class="input" v-model="account" disabled type="text" :placeholder="$t('reg.c3')" placeholder-class="placeholder" />
+		</view>
+		
+		<view class="row b-b">
+			<text class="tit">{{$t('safe.b3')}}</text>
+			<input class="input" v-model="password" type="password" :placeholder="$t('safe.b4')" placeholder-class="placeholder" />
+		</view>
+		
+		<view class="row b-b">
+			<text class="tit">{{$t('safe.a7')}}</text>
+			<input class="input" v-model="captcha" type="text" :placeholder="$t('safe.a6')" placeholder-class="placeholder" />
+			<view class="code" @click="verification">{{ countDown == 0 ? '验证码' : countDown }}</view>
+			
+			
+			
+		</view>
+	
+		<button class="add-btn" :class="{'bg-gray':loding}" @click="loding?'':confirm()">{{$t('set.a5')}}</button>
+	</view>
+</template>
+
+<script>
+import { verify } from '@/api/login.js';
+import { mapState } from 'vuex';
+import { registerReset } from '@/api/set.js';
+export default {
+	data() {
+		return {
+			time: '', //保存倒计时对象
+			countDown: 0, //倒计时
+			account: '', //手机号
+			captcha: '', //验证码
+			password: '' ,//新密码
+			loding:false,//是否载入中
+		};
+	},
+	computed: {
+		...mapState("user",['userInfo'])
+	},
+	onLoad() {
+		if(this.userInfo.account == null){
+			this.account = '';
+		}else{
+			this.account = this.userInfo.account;
+			this.show = false;
+		}
+	},
+	watch: {
+		// 监听倒计时
+		countDown(i) {
+			if (i == 0) {
+				clearInterval(this.time);
+			}
+		}
+	},
+	methods: {
+		//发送验证码
+		verification() {
+			let obj = this;
+			if (this.account == '') {
+				this.$api.msg(obj.$t("reg.a3"));
+				return;
+			}
+			if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(this.account)) {
+				this.$api.msg(obj.$t("safe.b8"));
+				return;
+			} 
+			// 判断是否在倒计时
+			if (obj.countDown > 0) {
+				return false;
+			} else {
+				obj.countDown = 60;
+				obj.time = setInterval(() => {
+					obj.countDown--;
+				}, 1000);
+				//调用验证码接口
+				verify({
+					phone: obj.account,
+					type: ''
+				})
+					.then(({ data }) => {})
+					.catch(err => {
+						console.log(err);
+					});
+			}
+		},
+		confirm(e) {
+			this.loding = true;
+			registerReset({
+				account: this.account,
+				captcha: this.captcha,
+				password: this.password,
+			})
+				.then(({ data }) => {
+					this.loding = false;
+					this.$api.msg(obj.$t("safe.d3"));
+				})
+				.catch(err => {
+					this.loding = false;
+					console.log(err);
+				});
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	background: #f3f3f3;
+}
+.row {
+	display: flex;
+	align-items: center;
+	position: relative;
+	padding: 0 30rpx;
+	height: 110rpx;
+	background: #fff;
+
+	.tit {
+		flex-shrink: 0;
+		width: 120rpx;
+		font-size: 30rpx;
+		color: $font-color-dark;
+	}
+	.input {
+		flex: 1;
+		font-size: 30rpx;
+		color: $font-color-dark;
+	}
+	.iconlocation {
+		font-size: 36rpx;
+		color: $font-color-light;
+	}
+}
+.add-btn {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	height: 100rpx;
+	margin: 60rpx auto;
+	font-size: $font-lg;
+	background-color: #FFF;
+	border-radius: 10rpx;
+	// box-shadow: 1px 2px 5px rgba(219, 63, 96, 0.4);
+}
+
+.bg-gray{
+	background-color: $color-gray;
+}
+.code {
+	color: #5dbc7c;
+	font-size: 23rpx;
+	border-left: 1px solid #eeeeee;
+	width: 150rpx;
+	flex-shrink: 0;
+	text-align: center;
+}
+</style>

+ 89 - 0
pages/user/set/set.vue

@@ -0,0 +1,89 @@
+<template>
+	<view class="container">
+		<uni-list>
+		    <uni-list-item :title="$t('safe.f6')" clickable showArrow  @click="navTo('/pages/user/set/userinfo')" ></uni-list-item>
+			<!-- <uni-list-item :title="$t('safe.f7')" clickable showArrow  @click="navTo('/pages/user/set/password')" ></uni-list-item> -->
+			<uni-list-item :title="$t('safe.d1')" clickable showArrow  @click="navTo('/pages/user/set/transaction')" ></uni-list-item>
+		</uni-list>
+		<view class="list-cell log-out-btn" @click="toLogout">
+			<text class="cell-tit">{{$t('accountSettings.a9')}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { logout } from '@/api/set.js';
+	import {  
+	    mapMutations  
+	} from 'vuex';
+	export default {
+		data() {
+			return {
+				
+			};
+		},
+		methods:{
+			...mapMutations('user',['logout']),
+			navTo(url){
+				uni.navigateTo({
+					url:url,
+					fail(red) {
+						console.log(red);
+					}
+				})
+			},
+			//退出登录
+			toLogout(){
+				let obj = this;
+				uni.showModal({
+				    content: this.$t('login.b7'),
+				    success: (e)=>{
+				    	if(e.confirm){
+							logout({}).then((e) => {
+								uni.navigateBack();
+							}).catch((e) => {
+								console.log(e);
+							})
+				    		obj.logout();
+				    	}
+				    }
+				});
+			},
+		}
+	}
+</script>
+
+<style lang='scss'>
+	page{
+		background: #f3f3f3;
+	}
+	.list-cell{
+		display:flex;
+		align-items:baseline;
+		padding: 20rpx $page-row-spacing;
+		line-height:60rpx;
+		position:relative;
+		background: #fff;
+		justify-content: center;
+		&.log-out-btn{
+			margin-top: 40rpx;
+			.cell-tit{
+				text-align: center;
+				margin-right: 0;
+			}
+		}
+		.cell-tit{
+			flex: 1;
+			font-size: $font-base + 2rpx;
+			color: $font-color-dark;
+			margin-right:10rpx;
+		}
+		.cell-tip{
+			font-size: $font-base;
+			color: $font-color-light;
+		}
+		switch{
+			transform: translateX(16rpx) scale(.84);
+		}
+	}
+</style>

+ 213 - 0
pages/user/set/transaction.vue

@@ -0,0 +1,213 @@
+<template>
+	<view class="container">
+		<view class="row b-b">
+			<text class="tit">{{$t('set.a3')}}</text>
+			<input class="input" disabled v-model="account" type="text" :placeholder="$t('reg.a3')"
+				placeholder-class="placeholder" />
+		</view>
+		<view class="row b-b">
+			<text class="tit">{{$t('reg.a8')}}</text>
+			<input class="input" v-model="password" type="password" :placeholder="$t('reg.a9')"
+				placeholder-class="placeholder" />
+		</view>
+		<view class="row b-b">
+			<text class="tit">{{$t('reg.b0')}}</text>
+			<input class="input" v-model="repeat" type="password" :placeholder="$t('reg.b1')"
+				placeholder-class="placeholder" />
+		</view>
+		<!-- <view class="row b-b">
+			<text class="tit">{{$t('reg.a6')}}</text>
+			<input class="input" v-model="captcha" type="text" :placeholder="$t('reg.a7')" placeholder-class="placeholder" />
+			<view class="code" @click="verification">{{ countDown == 0 ? $t('reg.c6') : countDown }}</view>
+		</view> -->
+		<button class="add-btn" :class="{'bg-gray':loding}"
+			@click="loding?'':confirm()">{{$t('common.submit')}}</button>
+	</view>
+</template>
+
+<script>
+	import {
+		verify
+	} from '@/api/login.js';
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		Reset
+	} from '@/api/set.js';
+	import detectEthereumProvider from '@metamask/detect-provider'
+	export default {
+		data() {
+			return {
+				time: '', //保存倒计时对象
+				countDown: 0, //倒计时
+				account: '', //手机号
+				captcha: '', //验证码
+				password: '', //密码
+				repeat: '', //确认密码
+				loding: false, //是否载入中
+			};
+		},
+		computed: {
+			...mapState("user", ['userInfo'])
+		},
+		onLoad() {
+			if (this.userInfo.account == null) {
+				this.account = '';
+			} else {
+				this.account = this.userInfo.account;
+				this.show = false;
+			}
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.b3"),
+			});
+		},
+		watch: {
+			// 监听倒计时
+			countDown(i) {
+				if (i == 0) {
+					clearInterval(this.time);
+				}
+			}
+		},
+		methods: {
+			//发送验证码
+			verification() {
+				let obj = this;
+				if (this.account == '') {
+					this.$api.msg(obj.$t("safe.b5"));
+					return;
+				}
+				// if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(this.account)) {
+				// 	this.$api.msg(obj.$t("safe.b8"));
+				// 	return;
+				// }
+				// 判断是否在倒计时
+				if (obj.countDown > 0) {
+					return false;
+				} else {
+					obj.countDown = 60;
+					obj.time = setInterval(() => {
+						obj.countDown--;
+					}, 1000);
+					//调用验证码接口
+					verify({
+							phone: obj.account,
+							type: ''
+						})
+						.then(({
+							data
+						}) => {})
+						.catch(err => {
+							console.log(err);
+						});
+				}
+			},
+
+			async confirm(e) {
+				this.loding = true;
+				uni.showLoading({
+					title: this.$t("userinfo.u23"),
+					mask: true
+				});
+				const provider = await detectEthereumProvider();
+				// 链接到MetaMask
+				ethereum.request({
+					method: 'eth_requestAccounts'
+				}).then((account) => {
+					console.log(account, 'account');
+					// this.$store.commit('accounts/connect_wallet', account[0]);
+					// localStorage.setItem('accounts', account)
+					const PKR_LOGIN = 'PKR_RESET' + (new Date()).getTime();
+					ethereum.request({
+						"method": "personal_sign",
+						"params": [
+							PKR_LOGIN,
+							account[0]
+						]
+					}).then((res) => {
+						Reset({
+								password: this.password,
+								repeat: this.repeat,
+								sign:res,
+								account: account[0],
+								msg:PKR_LOGIN
+							})
+							.then(() => {
+								this.loding = false;
+								uni.showToast({
+									title: this.$t("safe.d3"),
+									icon: "success",
+									mask: true
+								});
+							})
+							.catch(err => {
+								this.loding = false;
+								console.log(err);
+							});
+					});
+				});
+
+
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	page {
+		background: #f3f3f3;
+	}
+
+	.row {
+
+		display: flex;
+		align-items: center;
+		position: relative;
+		padding: 0 30rpx;
+		height: 110rpx;
+		background: $font-color-white;
+
+		.tit {
+			min-width: 130rpx;
+			flex-shrink: 0;
+			font-size: 30rpx;
+		}
+
+		.input {
+			flex: 1;
+			font-size: 30rpx;
+			color: $font-color-light;
+			padding-left: 20rpx;
+		}
+
+		.iconlocation {
+			font-size: 36rpx;
+			color: $font-color-light;
+		}
+	}
+
+	.add-btn {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		height: 100rpx;
+		margin: 60rpx auto;
+		font-size: $font-lg;
+		background-color: #FFF;
+		border: none;
+	}
+
+	.bg-gray {
+		background-color: $color-gray;
+	}
+
+	.code {
+		color: #000s;
+		font-size: 23rpx;
+		border-left: 1px solid #eeeeee;
+		width: 150rpx;
+		flex-shrink: 0;
+		text-align: center;
+	}
+</style>

+ 264 - 0
pages/user/set/userinfo.vue

@@ -0,0 +1,264 @@
+<template>
+	<view class="content">
+		<view class="row1">
+			<text class="tit">{{$t('set.a1')}}</text>
+			<view class="background-img" @click="imgsub"><image class="background-img" v-model="userInfo.avatar" :src="userInfo.avatar" mode="aspectFill"></image></view>
+		</view>
+		<view class="row">
+			<text class="tit">{{$t('set.a2')}}</text>
+			<input class="input" type="text" v-model="userInfo.nickname" placeholder-class="placeholder"/>
+		</view>
+		<vie<!-- w class="row">
+			<text class="tit">{{$t('set.a3')}}</text>
+			<view class="input">
+				{{userInfo.account}}
+			</view>
+		</view> -->
+		<!-- <view class="row">
+			<text class="tit">ID</text>
+			<input class="input" type="text"  disabled="true" v-model="userInfo.uid" placeholder-class="placeholder" />
+		</view> -->
+		<view class="list-cell log-out-btn" @click="confirm">
+			<text class="cell-tit">{{$t('set.a4')}}</text>
+		</view>
+		<uni-popup ref="popup" type="center">
+			<view class="psw-wrapper">
+				<view class="psw-title">{{$t('safe.f3')}}</view>
+				<input type="text" v-model="password" class="psw-ipt" />
+				<view class="psw-btn">
+					<text @click.stop="qx">{{$t('zy.b4')}}</text>
+					<text class="psw-qd" @click.stop="pswQd">{{$t('zy.b3')}}</text>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+import { mapState,mapMutations } from 'vuex';
+import { upload } from '@/api/order.js';
+import {userEdit,logout} from '@/api/set.js';
+export default {
+	data(){
+		return{
+			show:false,
+			password: '',
+		}
+	},
+	onLoad() {
+		console.log(this.userInfo)
+	},
+	computed: {
+		...mapState('user',['userInfo'])
+	},
+	methods: {
+		...mapMutations('user',['logout']),
+		imgsub() {
+			console.log('上传头像')
+			upload({
+				filename: ''
+			}).then(data => {
+				console.log("data",data);
+				this.userInfo.avatar = data[0].url;
+			})
+		},
+		confirm() {
+			userEdit({ avatar: this.userInfo.avatar ,nickname: this.userInfo.nickname})
+				.then(e => {
+					uni.showToast({
+						// title: '修改成功',
+						title: this.$t("safe.d3"),
+						icon:"success",
+						mask:true
+					});
+					setTimeout(()=> {
+						uni.switchTab({
+							url:'/pages/user/user'
+						});
+					}, 1000);
+					console.log(e);
+				})
+				.catch(e => {
+					console.log(e);
+				});
+				
+		},
+		toLogout(){
+			let obj = this;
+			uni.showModal({
+			    content:  this.$t('login.b7'),
+			    success: (e)=>{
+			    	if(e.confirm){
+						logout({}).then((e) => {
+							uni.navigateBack();
+						}).catch((e) => {
+							console.log(e);
+						})
+			    		obj.logout();
+			    	}
+			    }
+			});
+		},
+		cancel(){
+			// this.$refs.popup.open();
+			let obj = this;
+			uni.showModal({
+				content:  this.$t('login.b7'),
+				success: e => {
+					if (e.confirm) {
+						logout({}).then(e => {
+								obj.logout();
+								uni.switchTab({
+									url: '/pages/index/index'
+								})
+							})
+							.catch(e => {
+								console.log(e);
+							});
+					}
+				}
+			});
+		},
+		qx() {
+			this.password = '';
+			this.$refs.popup.close();
+		},
+		pswQd() {
+			if(this.password != this.userInfo.phone){
+				this.$refs.popup.close();
+				this.password = '';
+				this.$api.msg(obj.$t("safe.f3"))
+				return
+			}
+			this.$refs.popup.close();
+			this.password = '';
+			this.$api.msg(obj.$t("safe.f4"))
+		}
+	}
+}
+</script>
+
+<style lang="scss">
+	page{
+		background-color: #f3f3f3;
+	}
+	.list-cell{
+		display:flex;
+		align-items:baseline;
+		padding: 20rpx $page-row-spacing;
+		line-height:60rpx;
+		position:relative;
+		background: #fff;
+		justify-content: center;
+		&.log-out-btn{
+			margin-top: 40rpx;
+			.cell-tit{
+				text-align: center;
+				margin-right: 0;
+			}
+		}
+		.cell-tit{
+			flex: 1;
+			font-size: $font-base + 2rpx;
+			color: $font-color-dark;
+			margin-right:10rpx;
+		}
+	}
+	.row1 {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		position: relative;
+		padding: 0 30upx;
+		height: 110upx;
+		background: #fff;
+		margin-bottom: 20upx;
+		.tit {
+			flex-shrink: 0;
+			width: 120upx;
+			font-size: $font-lg;
+			color: $font-color-dark;
+		}
+		
+		.background-img {
+			width: 80rpx;
+			height: 80rpx;
+			border-radius: 50%;
+			background: #f2f2f2;
+		}
+	}
+	.row {
+		display: flex;
+		align-items: center;
+		padding: 0 30upx;
+		height: 110upx;
+		background: #fff;
+		border-bottom:1px solid $border-color-light ;
+		.tit {
+			flex-shrink: 0;
+			width: 120upx;
+			font-size: $font-lg;
+			color: $font-color-dark;
+		}
+		.input {
+			flex: 1;
+			text-align: right;
+			font-size: $font-base;
+			color: $color-gray;
+		}
+	}
+	.add-btn {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		margin: 158rpx auto 30rpx;
+		width: 560rpx;
+		height: 80rpx;
+		background: #feca00;
+		border-radius: 40px;
+		color: #FFFFFF;
+	}
+	.out {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		margin: 0 auto 30rpx;
+		width: 560rpx;
+		height: 80rpx;
+		border: 1px solid  #feca00;
+		background: #FFFFFF;
+		border-radius: 40px;
+		color:  #feca00;
+	}
+	.psw-wrapper {
+		width: 548rpx;
+		height: 344rpx;
+		background-color: #ffffff;
+		.psw-title {
+			width: 100%;
+			font-size: 35rpx;
+			padding: 43rpx 0 49rpx;
+			text-align: center;
+			font-weight: 800;
+		}
+		.psw-ipt {
+			display: block;
+			background-color: #dce3ed;
+			height: 90rpx;
+			width: 464rpx;
+			padding-left: 30rpx;
+			margin: 0 auto;
+			font-size: 80rpx;
+		}
+		.psw-btn text {
+			display: inline-block;
+			text-align: center;
+			width: 50%;
+			padding-top: 29rpx;
+			font-size: 35rpx;
+		}
+		.psw-qd {
+			color: #32C6FF;
+		}
+	}
+</style>

+ 207 - 0
pages/user/shareQrCode.vue

@@ -0,0 +1,207 @@
+<template>
+	<view class="all">
+		<view class="list" v-for="item in list">
+			<view class="flex padding-b-20">
+				<view class="li">{{$t('set.a7')}}{{item.room.no}}{{$t('set.a8')}}</view>
+				<view class="lis" v-if="item.result === 1">
+					<view class="liss green">{{$t('enter.a5')}}</view>
+				</view>
+				<view class="lis" v-if="item.result === 0">
+					<view class="liss red">{{$t('enter.a6')}}</view>
+				</view>
+				<view class="lis" v-if="item.status === 0">
+					<view class="liss primary">{{$t('enter.a4')}}</view>
+				</view>
+			</view>
+			<view class="listT">
+				<!-- <view class="TT flex">
+					<view class="lsT">{{$t('gameList.a2')}}</view>
+					<view class="lisT">{{item.room.game.timebar}}</view>
+				</view> -->
+				<view class="TT flex">
+					<view class="lsT">{{$t('gameList.a4')}}</view>
+					<view class="lisT">{{item.num}}U</view>
+				</view>
+				<view class="TT flex">
+					<view class="lsT">{{$t('gameList.a7')}}</view>
+					<view class="lisT green" v-if="item.bet==1">{{ $t("enter.u6") }}</view>
+					<view class="lisT red" v-if="item.bet==2">{{ $t("enter.u4") }}</view>
+					<view class="lisT green" v-if="item.bet==3">{{ $t("enter.u5") }}</view>
+					<view class="lisT red" v-if="item.bet==4">{{ $t("enter.u7") }}</view>
+				</view>
+				<view class="TT flex">
+					<view class="lsT">{{$t('gameList.a8')}}</view>
+					<view class="lisT">{{item.get}}U</view>
+				</view>
+				<view class="TT flex">
+					<view class="lsT">{{$t('gameList.a9')}}</view>
+					<view class="flex-start">
+						<template v-for="it in item.room.arr " v-if="it.value==1">
+							<view class="lisT green" v-if="it.type==1">{{ $t("enter.u6") }}</view>
+							<view class="lisT green" v-if="it.type==3">{{ $t("enter.u5") }}</view>
+							<view class="lisT red" v-if="it.type==2">{{ $t("enter.u4") }}</view>
+							<view class="lisT red" v-if="it.type==4">{{ $t("enter.u7") }}</view>
+						</template>
+					</view>
+				</view>
+				<view class="TT flex">
+					<view class="lsT">{{$t('gameList.a10')}}</view>
+					<view class="lisT flex" v-if="item.room.result_info">
+					<image v-for="ls in item.room.result_info" class="dice"
+						:src="`../../static/img/dice${ls}.png`" mode="scaleToFill"></image>
+					</view>
+				</view>
+				<view class="TT flex">
+					<view class="lsT">{{$t('gameList.a5')}}</view>
+					<view class="lisT">{{item.open_time}}</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+	import {
+		gameBetList
+	} from '@/api/game.js'
+	import {
+		getTime
+	} from '@/utils/rocessor.js';
+	export default {
+		data() {
+			return {
+				id: 0,
+				page: 1,
+				limit: 10,
+				list: []
+			};
+		},
+		onLoad() {
+			this.gameBetList()
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.a9"),
+			});
+		},
+		onReachBottom() {
+			this.gameBetList()
+		},
+		//下拉刷新
+		methods: {
+			// 互娱记录
+			gameBetList() {
+				let that = this
+				if (that.loadingType == 'loading' || that.loadingType == 'noMore') {
+					return
+				}
+				gameBetList({
+					page: that.page,
+					limit: that.limit,
+					id: that.id,
+				}).then(res => {
+					let list = res.data.bet_log.map((res) => {
+						res.num = +res.num;
+						res.get = +res.get;
+						res.room.result_info =  res.room.result_info.split(",");
+						let result = res.room.result
+						if (result) {
+							let arr = [];
+							const ar = result.split(",")
+							for (let i = 0; i < ar.length; i++) {
+								const s = ar[i].split(':');
+								arr.push({
+									type: s[0],
+									value: s[1]
+								})
+							}
+							res.room.arr = arr;
+						}
+						res.open_time = getTime(res.open_time);
+						return res
+					})
+					that.list = that.list.concat(list)
+					console.log('1111111', list);
+					that.page++
+					if (list.length == that.limit) {
+						that.loadingType = 'more'
+					} else {
+						that.loadingType = 'noMore'
+					}
+					that.loaded = true
+				})
+			}
+
+		}
+	};
+</script>
+
+<style lang="scss">
+	.all {
+		color: #FFFFFF;
+		padding: 30rpx;
+		line-height: 1;
+	}
+
+	.list {
+		background: #191A1F;
+		box-shadow: 0rpx 5rpx 24rpx 0rpx rgba(4, 0, 0, 0.06);
+		border-radius: 15rpx;
+		padding: 30rpx;
+		margin-bottom: 30rpx;
+
+		.li {
+			font-size: $font-lg;
+			font-weight: bold;
+		}
+
+		.lis {
+			.liss {
+				border-radius: 5rpx;
+				padding: 10rpx 20rpx;
+				font-size: 22rpx;
+				font-weight: 500;
+
+				&.red {
+					background: $color-yellow;
+				}
+
+				&.green {
+					background: $color-green;
+				}
+
+				&.primary {
+					background: #01ebf6;
+				}
+			}
+		}
+
+	}
+
+	.listT {
+		.TT {
+			margin-top: 20rpx;
+
+			.lsT {
+				font-weight: 500;
+				color: #999999;
+				font-size: $font-base;
+				min-width: 140rpx;
+			}
+
+			.lisT {
+				font-size: $font-lg;
+				font-weight: bold;
+				.dice {
+					width: 54rpx;
+					height: 54rpx;
+					margin-left: 10rpx;
+				}
+				&.red {
+					color: #df5660;
+				}
+
+				&.green {
+					color: $color-green;
+				}
+			}
+		}
+	}
+</style>

+ 129 - 0
pages/user/vip/details.vue

@@ -0,0 +1,129 @@
+<template>
+	<view class="">
+		<view class="list margin-t-20 margin-c-30" v-for="(item, ind) in list" :key="ind">
+			<view class="top flex">
+				<view class="nc clamp">{{item.nickname}}</view>
+				<image class="img margin-l-20" src="/static/shouye/huiyuan.png" mode=""></image>
+			</view>
+			<navigator :url="`/pages/user/vip/details?id=${item.uid}`">
+			<view class="center padding-v-30 flex" >
+				<view class="sj">{{item.time}}</view>
+				<view class="flex-start">
+					<view class="xq margin-r-10">{{$t('huiyuan.a5')}}</view>
+					<image class="ima" src="/static/icon/jt.png" mode="scaleToFill"></image>
+				</view>
+			</view>
+			</navigator>
+			<view class="last flex padding-t-30">
+				<view>
+					<text class="left">{{$t('huiyuan.a6')}}:</text>
+					<text class="leftT">{{item.join_usdt}}</text>
+				</view>
+				<view>
+					<text class="right">{{$t('huiyuan.a7')}}:</text>
+					<text class="rightT">{{item.childCount}}</text>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		spread_se
+	} from "@/api/user.js"
+	
+	export default {
+		data() {
+			return {
+				id: '',
+				page: 1,
+				limit: 10,
+				loadingType: 'more',
+				loaded: false,
+				list: [],
+			};
+		},
+		onLoad(option) {
+			console.log('载入');
+			this.id = option.id;
+			this.getList()
+			
+		},
+		onReachBottom() {
+			this.getList()
+		},
+		methods:{
+			// 获取列表
+			getList(){
+				let that = this
+				if (that.loadingType == 'loading' || that.loadingType == 'noMore') {
+					return
+				}
+				that.loadingType = "loading";
+				spread_se({
+					page: that.page,
+					limit: that.limit,
+				},that.id).then(({
+					data
+				}) => {
+					let list = data.list
+					that.list = that.list.concat(list)
+					if (list.length == that.limit) {
+						that.loadingType = 'more'
+					} else {
+						that.loadingType = 'noMore'
+					}
+					that.loaded = true
+				}).catch(e => {
+					console.log(e);
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+.list {
+		background: #191A1F;
+		border-radius: 16rpx;
+		padding: 30rpx;
+
+		.top {
+			.nc {
+				font-size: $font-lg;
+				font-weight: bold;
+				color: #FFFFFF;
+				flex-grow: 1;
+			}
+
+			.img {
+				flex-shrink: 0;
+				width: 100rpx;
+				height: 32rpx;
+			}
+		}
+
+		.center {
+			border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+			.ima {
+				width: 13rpx;
+				height: 19rpx;
+			}
+		}
+		.center,.last{
+			font-weight: 500;
+			font-size: $font-base;
+			color: #999999;
+		}
+		.last {
+			.leftT {
+				color: #b98134;
+			}
+
+			.rightT {
+				color: #ffffff;
+			}
+		}
+	}
+</style>

+ 220 - 0
pages/user/vip/tabulation.vue

@@ -0,0 +1,220 @@
+<template>
+	<view class="all">
+		<view class="row flex">
+			<view class="rowItem">
+				<view class="shu">{{total || 0}}</view>
+				<view class="wenben">{{$t('huiyuan.a1')}}</view>
+			</view>
+			<view class="rowItem">
+				<view class="shu">{{group_num || 0}}</view>
+				<view class="wenben">{{$t('huiyuan.a2')}}</view>
+			</view>
+		
+		</view>
+		<view class="row flex margin-t-20">
+			<view class="rowItem">
+				<view class="shu">{{totalLevel || 0}}</view>
+				<view class="wenben">{{$t('huiyuan.a3')}}</view>
+			</view>
+			<view class="rowItem">
+				<view class="shu">{{valid_user || 0}}</view>
+				<view class="wenben">{{$t('huiyuan.a4')}}</view>
+			</view>
+		</view>
+
+		<view class="list margin-t-20 margin-c-30" v-for="(item, ind) in list" :key="ind">
+			<view class="top flex">
+				<view class="nc clamp">{{item.nickname}}</view>
+				<image class="img margin-l-20" src="/static/shouye/huiyuan.png" mode=""></image>
+			</view>
+			<navigator :url="`/pages/user/vip/details?id=${item.uid}`">
+			<view class="center padding-v-30 flex" >
+				<view class="sj">{{item.time}}</view>
+				<view class="flex-start">
+					<view class="xq margin-r-10">{{$t('huiyuan.a5')}}</view>
+					<image class="ima" src="/static/icon/jt.png" mode="scaleToFill"></image>
+				</view>
+			</view>
+			</navigator>
+			<view class="last flex padding-t-30">
+				<view>
+					<text class="left">{{$t('huiyuan.a6')}}:</text>
+					<text class="leftT">{{item.join_usdt}}</text>
+				</view>
+				<view>
+					<text class="right">{{$t('huiyuan.a7')}}:</text>
+					<text class="rightT">{{item.childCount}}</text>
+				</view>
+			</view>
+		</view>
+		<view class="bto">
+
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex';
+	import {
+		spread,
+		getUserInfo
+	} from "@/api/user.js"
+	export default {
+		data() {
+			return {
+				page: 1,
+				limit: 10,
+				loadingType: 'more',
+				loaded: false,
+				list: [],
+				group_num: '', //团队人数
+				total: '', // 用户总数
+				totalLevel: '', // 账户总数
+				valid_user: '', // 有效账户
+			};
+		},
+		onLoad(option) {
+			this.spread()
+
+			uni.setNavigationBarTitle({
+				title: this.$t("tab.b1"),
+			});
+		},
+
+		computed: {
+			...mapState('user', ['userInfo', 'orderInfo', 'hasLogin'])
+		},
+		onReachBottom() {
+			this.spread()
+		},
+		methods: {
+			// 会员记录
+			spread() {
+				let that = this
+				if (that.loadingType == 'loading' || that.loadingType == 'noMore') {
+					return
+				}
+				that.loadingType = "loading";
+				spread({
+					page: that.page,
+					limit: that.limit,
+					// id: that.userInfo.uid,
+// <<<<<<< HEAD
+				// }).then(res => {
+				// 	let data = res.data
+				// 	console.log('1111111', data);
+				// 	this.group_num = data.group_num
+				// 	this.total = data.total
+				// 	this.totalLevel = data.totalLevel
+				// 	this.valid_user = data.valid_user
+					
+				// 	this.list = res.data.list
+				// 	console.log('list', this.list);
+				// }).catch(e=>{
+// =======
+				}).then(({
+					data
+				}) => {
+					let list = data.list
+					that.list = that.list.concat(list)
+					that.group_num = data.group_num
+					that.total = data.total
+					that.totalLevel = data.totalLevel
+					that.valid_user = data.valid_user
+
+					if (list.length == that.limit) {
+						that.loadingType = 'more'
+					} else {
+						that.loadingType = 'noMore'
+					}
+					that.loaded = true
+				}).catch(e => {
+// >>>>>>> ec643268e144bb15fc39a442eec94ca3d04a70ac
+					console.log(e);
+				})
+			},
+		}
+	};
+</script>
+
+<style lang="scss">
+	.all {
+		width: 750rpx;
+		background-color: $page-color-base;
+		line-height: 1;
+	}
+
+	.row {
+		padding: 0 30rpx;
+
+		.rowItem {
+			background: #191A1F;
+			border-radius: 10rpx;
+			width: 48%;
+			text-align: center;
+			padding: 40rpx 0;
+
+			.wenben {
+				font-size: 28rpx;
+				font-weight: 500;
+				color: #FFFFFF;
+			}
+
+			.shu {
+				font-size: 46rpx;
+				font-weight: bold;
+				color: #FEB041;
+			}
+		}
+	}
+
+	.list {
+		background: #191A1F;
+		border-radius: 16rpx;
+		padding: 30rpx;
+
+		.top {
+			.nc {
+				font-size: $font-lg;
+				font-weight: bold;
+				color: #FFFFFF;
+				flex-grow: 1;
+			}
+
+			.img {
+				flex-shrink: 0;
+				width: 100rpx;
+				height: 32rpx;
+			}
+		}
+
+		.center {
+			border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+
+			.ima {
+				width: 13rpx;
+				height: 19rpx;
+			}
+		}
+
+		.center,
+		.last {
+			font-weight: 500;
+			font-size: $font-base;
+			color: #999999;
+		}
+
+		.last {
+			.leftT {
+				color: #b98134;
+			}
+
+			.rightT {
+				color: #ffffff;
+			}
+		}
+	}
+</style>

File diff suppressed because it is too large
+ 0 - 0
plugin/jweixin-module/index.js


+ 1645 - 0
plugin/vue-i18n/CHANGELOG.md

@@ -0,0 +1,1645 @@
+
+## v8.21.0 (2020-08-13)
+
+#### :star: New Features
+* [#972](https://github.com/kazupon/vue-i18n/pull/972) feat: message function ([@kazupon](https://github.com/kazupon))
+
+#### :pencil: Documentation
+* [#961](https://github.com/kazupon/vue-i18n/pull/961) Update link to Formatter Interface ([@JohJohan](https://github.com/JohJohan))
+
+#### Committers: 3
+- Alexander Sokolov ([@Alex-Sokolov](https://github.com/Alex-Sokolov))
+- Johan ([@JohJohan](https://github.com/JohJohan))
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v8.20.0 (2020-07-30)
+
+#### :star: New Features
+* [#959](https://github.com/kazupon/vue-i18n/pull/959) i18n-n component local components passing ([@kazupon](https://github.com/kazupon))
+* [#928](https://github.com/kazupon/vue-i18n/pull/928) :zap: improvement(interpolation): enable passage of local components to tag prop ([@vhoyer](https://github.com/vhoyer))
+
+#### Committers: 2
+- Vinícius Hoyer ([@vhoyer](https://github.com/vhoyer))
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v8.19.0 (2020-07-25)
+
+#### :star: New Features
+* [#942](https://github.com/kazupon/vue-i18n/pull/942) Add vetur support for tags and attributes ([@phiter](https://github.com/phiter))
+
+#### :pencil: Documentation
+* [#925](https://github.com/kazupon/vue-i18n/pull/925) Added missing quote ([@fschlag](https://github.com/fschlag))
+* [#921](https://github.com/kazupon/vue-i18n/pull/921) Add lost pluralizationRules option to documentation ([@AleksandrSl](https://github.com/AleksandrSl))
+* [#920](https://github.com/kazupon/vue-i18n/pull/920) Make link to API and Guide top level ([@AleksandrSl](https://github.com/AleksandrSl))
+
+#### Committers: 3
+- Aleksandr ([@AleksandrSl](https://github.com/AleksandrSl))
+- Florian Schlag ([@fschlag](https://github.com/fschlag))
+- Phiter Fernandes ([@phiter](https://github.com/phiter))
+
+
+## v8.18.2 (2020-06-08)
+
+#### :zap: Improved Features
+* [#917](https://github.com/kazupon/vue-i18n/pull/917) fix: improve IVueI18n interface ([@kazupon](https://github.com/kazupon))
+
+#### :pencil: Documentation
+* [#902](https://github.com/kazupon/vue-i18n/pull/902) docs: [RU] Translation update ([@Alex-Sokolov](https://github.com/Alex-Sokolov))
+* [#901](https://github.com/kazupon/vue-i18n/pull/901) docs: (zh) inverse $d $n ([@stan-chen](https://github.com/stan-chen))
+
+#### Committers: 4
+- Alexander Sokolov ([@Alex-Sokolov](https://github.com/Alex-Sokolov))
+- Rafał Chłodnicki ([@rchl](https://github.com/rchl))
+- Stanley Chen ([@stan-chen](https://github.com/stan-chen))
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v8.18.1 (2020-05-27)
+
+#### :bug: Bug Fixes
+* [#896](https://github.com/kazupon/vue-i18n/pull/896) Fix flow types and enable flow types testing on CI ([@rchl](https://github.com/rchl))
+
+#### Committers: 1
+- Rafał Chłodnicki ([@rchl](https://github.com/rchl))
+
+
+## v8.18.0 (2020-05-26)
+
+#### :star: New Features
+* [#892](https://github.com/kazupon/vue-i18n/pull/892) Add onComponentInstanceCreated constructor option ([@rchl](https://github.com/rchl))
+
+#### :zap: Improved Features
+* [#890](https://github.com/kazupon/vue-i18n/pull/890) chore: set up linting for typescript definitions ([@rchl](https://github.com/rchl))
+
+#### Committers: 1
+- Rafał Chłodnicki ([@rchl](https://github.com/rchl))
+
+
+## v8.17.7 (2020-05-19)
+
+#### :bug: Bug Fixes
+* [#882](https://github.com/kazupon/vue-i18n/pull/882) fix v-t pluralisation when choice is 0 ([@mikejacoutot](https://github.com/mikejacoutot))
+
+#### Committers: 1
+- [@mikejacoutot](https://github.com/mikejacoutot)
+
+
+## v8.17.6 (2020-05-15)
+
+#### :bug: Bug Fixes
+* [#880](https://github.com/kazupon/vue-i18n/pull/880) Don't delete _i18n in beforeDestroy ([@danimoh](https://github.com/danimoh))
+
+#### :zap: Improved Features
+* [#878](https://github.com/kazupon/vue-i18n/pull/878) Allow component interpolation without root element ([@danimoh](https://github.com/danimoh))
+
+#### :pencil: Documentation
+* [#875](https://github.com/kazupon/vue-i18n/pull/875) Add new 3rd party tool ([@danigayosog](https://github.com/danigayosog))
+* [#872](https://github.com/kazupon/vue-i18n/pull/872) docs: fixes ([@Alex-Sokolov](https://github.com/Alex-Sokolov))
+* [#871](https://github.com/kazupon/vue-i18n/pull/871) update pluralization.md ([@Timibadass](https://github.com/Timibadass))
+
+#### Committers: 4
+- Alexander Sokolov ([@Alex-Sokolov](https://github.com/Alex-Sokolov))
+- Daniel ([@danigayosog](https://github.com/danigayosog))
+- Timi Omoyeni ([@Timibadass](https://github.com/Timibadass))
+- [@danimoh](https://github.com/danimoh)
+
+
+## v8.17.5 (2020-05-10)
+
+#### :bug: Bug Fixes
+* [#869](https://github.com/kazupon/vue-i18n/pull/869) fix: not string method access error ([@kazupon](https://github.com/kazupon))
+
+#### :pencil: Documentation
+* [#867](https://github.com/kazupon/vue-i18n/pull/867) docs: [RU] Translation ([@Alex-Sokolov](https://github.com/Alex-Sokolov))
+* [#865](https://github.com/kazupon/vue-i18n/pull/865) improvement(docs): extend Hot reloading section ([@caugner](https://github.com/caugner))
+
+#### Committers: 3
+- Alexander Sokolov ([@Alex-Sokolov](https://github.com/Alex-Sokolov))
+- Claas Augner ([@caugner](https://github.com/caugner))
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v8.17.4 (2020-04-26)
+
+#### :bug: Bug Fixes
+* [#859](https://github.com/kazupon/vue-i18n/pull/859) fix datetime format cache ([@kazupon](https://github.com/kazupon))
+* [#858](https://github.com/kazupon/vue-i18n/pull/858) fix datetime and number format fallbacking ([@kazupon](https://github.com/kazupon))
+* [#857](https://github.com/kazupon/vue-i18n/pull/857) fix: alternative array includes ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v8.17.3 (2020-04-19)
+
+#### :zap: Improved Features
+* [#846](https://github.com/kazupon/vue-i18n/pull/846) add key to postTranslation ([@dmitryuk](https://github.com/dmitryuk))
+
+#### :pencil: Documentation
+* [#847](https://github.com/kazupon/vue-i18n/pull/847) docs: Update /api/README.md ([@Alex-Sokolov](https://github.com/Alex-Sokolov))
+
+#### Committers: 2
+- Alexander Dmitryuk ([@dmitryuk](https://github.com/dmitryuk))
+- Alexander Sokolov ([@Alex-Sokolov](https://github.com/Alex-Sokolov))
+
+
+## v8.17.2 (2020-04-18)
+
+#### :zap: Improved Features
+* [#844](https://github.com/kazupon/vue-i18n/pull/844) Use plain object instead of Map, which is not supported in IE9/10 ([@exoego](https://github.com/exoego))
+
+#### Committers: 1
+- TATSUNO Yasuhiro ([@exoego](https://github.com/exoego))
+
+
+## v8.17.1 (2020-04-16)
+
+#### :bug: Bug Fixes
+* [#840](https://github.com/kazupon/vue-i18n/pull/840) fix: altnative endsWidth ([@kazupon](https://github.com/kazupon))
+
+#### :pencil: Documentation
+* [#837](https://github.com/kazupon/vue-i18n/pull/837) Fix typo ([@ninofiliu](https://github.com/ninofiliu))
+
+#### Committers: 2
+- Nino Filiu ([@ninofiliu](https://github.com/ninofiliu))
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v8.17.0 (2020-04-11)
+
+#### :star: New Features
+* [#829](https://github.com/kazupon/vue-i18n/pull/829) #138 Fallback Locale as array for cascading fallbacks ([@mmokross](https://github.com/mmokross))
+
+#### :pencil: Documentation
+* [#834](https://github.com/kazupon/vue-i18n/pull/834) Add capitalize default modifier in doc ([@alexandreDavid](https://github.com/alexandreDavid))
+* [#832](https://github.com/kazupon/vue-i18n/pull/832) fix in examples of "Custom pluralization" ([@Perlover](https://github.com/Perlover))
+
+#### Committers: 4
+- Alexandre David ([@alexandreDavid](https://github.com/alexandreDavid))
+- Kobayashi Kazuhiro ([@kzhrk](https://github.com/kzhrk))
+- Michael Mokroß ([@mmokross](https://github.com/mmokross))
+- Perlover ([@Perlover](https://github.com/Perlover))
+
+
+## v8.16.0 (2020-03-27)
+
+#### :star: New Features
+* [#822](https://github.com/kazupon/vue-i18n/pull/822) post translation hooking feature ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v8.15.7 (2020-03-25)
+
+#### :bug: Bug Fixes
+* [#819](https://github.com/kazupon/vue-i18n/pull/819) Fixed bug when changing number format runtime ([@slischka](https://github.com/slischka))
+
+#### Committers: 1
+- Jiří Slischka ([@slischka](https://github.com/slischka))
+
+
+## v8.15.6 (2020-03-23)
+
+#### :bug: Bug Fixes
+* [#817](https://github.com/kazupon/vue-i18n/pull/817) Bugfix : 'setLocaleMessage' / 'mergeLocaleMessage' doesn't work if 'warnHtmlInMessage' is set to 'error'  ([@aym3nb](https://github.com/aym3nb))
+
+#### :pencil: Documentation
+* [#816](https://github.com/kazupon/vue-i18n/pull/816) Update fallback.md ([@scoutrul](https://github.com/scoutrul))
+
+#### Committers: 3
+- Anton ([@scoutrul](https://github.com/scoutrul))
+- Aymen Bareche ([@aym3nb](https://github.com/aym3nb))
+- TATSUNO Yasuhiro ([@exoego](https://github.com/exoego))
+
+
+## v8.15.5 (2020-03-07)
+
+#### :star: Features
+* [#787](https://github.com/kazupon/vue-i18n/pull/787) Add a 'capitalize' default modifier for linked message ([@charlesmass](https://github.com/charlesmass))
+
+#### :zap: Improvement Features
+* [#794](https://github.com/kazupon/vue-i18n/pull/794) Support returning 'string' type for customized interpolation ([@sihyeonn](https://github.com/sihyeonn))
+
+#### :pencil: Documentation
+* [#791](https://github.com/kazupon/vue-i18n/pull/791) Revise fallback.md ([@jlebar](https://github.com/jlebar))
+
+#### Committers: 4
+- Justin Lebar ([@jlebar](https://github.com/jlebar))
+- L M ([@charlesmass](https://github.com/charlesmass))
+- Sihyeon Jang ([@sihyeonn](https://github.com/sihyeonn))
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+<a name="8.15.4"></a>
+## [8.15.4](https://github.com/kazupon/vue-i18n/compare/v8.15.3...v8.15.4) (2020-02-25)
+
+
+### :bug: Bug Fixes
+
+* **index:** improve formatFallbackMessages code (#779) (#783) by [@masongzhi](https://github.com/masongzhi) ([53895b9](https://github.com/kazupon/vue-i18n/commit/53895b9)))
+
+### :up: Updates
+
+* some fixes ([8a9a950](https://github.com/kazupon/vue-i18n/commit/8a9a950))
+
+
+
+<a name="8.15.3"></a>
+## [8.15.3](https://github.com/kazupon/vue-i18n/compare/v8.15.2...v8.15.3) (2019-12-18)
+
+
+### :zap: Improvements
+
+* **index:** fix mergeLocaleMessage. add changes notification on merging with an empty target object ([#752](https://github.com/kazupon/vue-i18n/issues/752)) by [@jekill](https://github.com/jekill) ([048eac5](https://github.com/kazupon/vue-i18n/commit/048eac5)), closes [#752](https://github.com/kazupon/vue-i18n/issues/752)
+
+
+
+<a name="8.15.2"></a>
+## [8.15.2](https://github.com/kazupon/vue-i18n/compare/v8.15.1...v8.15.2) (2019-12-18)
+
+
+### :bug: Bug Fixes
+
+* **index:** Fix exception when using unit number formatting by [@simonjodet](https://github.com/simonjodet) ([194b801](https://github.com/kazupon/vue-i18n/commit/194b801)), closes [#750](https://github.com/kazupon/vue-i18n/issues/750) [#751](https://github.com/kazupon/vue-i18n/issues/751)
+
+
+
+<a name="8.15.1"></a>
+## [8.15.1](https://github.com/kazupon/vue-i18n/compare/v8.15.0...v8.15.1) (2019-11-27)
+
+
+### :zap: Improvements
+
+* **mixin:** change to custom blocks parse error ([a9858be](https://github.com/kazupon/vue-i18n/commit/a9858be))
+
+
+
+<a name="8.15.0"></a>
+# [8.15.0](https://github.com/kazupon/vue-i18n/compare/v8.14.1...v8.15.0) (2019-10-16)
+
+
+### :star: New Features
+
+* Add constructor option for custom modifiers ([#724](https://github.com/kazupon/vue-i18n/issues/724)) by [@epaezrubio](https://github.com/epaezrubio) ([3217212](https://github.com/kazupon/vue-i18n/commit/3217212)), closes [#724](https://github.com/kazupon/vue-i18n/issues/724)
+
+
+
+<a name="8.14.1"></a>
+## [8.14.1](https://github.com/kazupon/vue-i18n/compare/v8.14.0...v8.14.1) (2019-09-12)
+
+
+### :bug: Bug Fixes
+
+* **path:** fix branket key error ([8d2aba7](https://github.com/kazupon/vue-i18n/commit/8d2aba7))
+* **component:** Fix interpolation component when there are empty text nodes ([547cdd1](https://github.com/kazupon/vue-i18n/commit/547cdd1)) by [@Demivan](https://github.com/Demivan)
+
+
+
+<a name="8.14.0"></a>
+# [8.14.0](https://github.com/kazupon/vue-i18n/compare/v8.13.0...v8.14.0) (2019-08-12)
+
+
+### :star: New Features
+
+* fallback formatting ([#637](https://github.com/kazupon/vue-i18n/issues/637)) by [@sebwas](https://github.com/sebwas) ([bf9929c](https://github.com/kazupon/vue-i18n/commit/bf9929c)), closes [#637](https://github.com/kazupon/vue-i18n/issues/637)
+* support slots syntax for component interpolation ([#685](https://github.com/kazupon/vue-i18n/issues/685)) by [@aavondet](https://github.com/aavondet) ([71ca843](https://github.com/kazupon/vue-i18n/commit/71ca843)), closes [#685](https://github.com/kazupon/vue-i18n/issues/685)
+
+
+
+<a name="8.13.0"></a>
+# [8.13.0](https://github.com/kazupon/vue-i18n/compare/v8.12.0...v8.13.0) (2019-08-09)
+
+
+### :star: New Features
+
+* datetime/number formats fallback warning filter ([46de19e](https://github.com/kazupon/vue-i18n/commit/46de19e)), closes [#558](https://github.com/kazupon/vue-i18n/issues/558)
+* fallback translation warning filter ([69fc798](https://github.com/kazupon/vue-i18n/commit/69fc798))
+* translation missing warning filter ([666dc9d](https://github.com/kazupon/vue-i18n/commit/666dc9d))
+
+
+
+<a name="8.12.0"></a>
+# [8.12.0](https://github.com/kazupon/vue-i18n/compare/v8.11.2...v8.12.0) (2019-07-09)
+
+
+### :star: New Features
+
+* **mixin:** shared locale messages feature ([82543de](https://github.com/kazupon/vue-i18n/commit/82543de))
+
+
+### :zap: Improvements
+
+* **typing:** sharedMessages option type ([6967a15](https://github.com/kazupon/vue-i18n/commit/6967a15))
+
+
+
+<a name="8.11.2"></a>
+## [8.11.2](https://github.com/kazupon/vue-i18n/compare/v8.11.1...v8.11.2) (2019-04-30)
+
+
+### :bug: Bug Fixes
+
+* bug(mixin): fix SSR memory leak by moving subscribeDataChanging calls into beforeMount ([#572](https://github.com/kazupon/vue-i18n/issues/572)) by [@Pindar](https://github.com/Pindar) ([32b5795](https://github.com/kazupon/vue-i18n/commit/32b5795)), closes [#572](https://github.com/kazupon/vue-i18n/issues/572)
+
+
+
+<a name="8.11.1"></a>
+## [8.11.1](https://github.com/kazupon/vue-i18n/compare/v8.11.0...v8.11.1) (2019-04-26)
+
+
+### :bug: Bug Fixes
+
+* fix ES Modules distribution ([bb631a1](https://github.com/kazupon/vue-i18n/commit/bb631a1))
+
+
+
+<a name="8.11.0"></a>
+# [8.11.0](https://github.com/kazupon/vue-i18n/compare/v8.10.0...v8.11.0) (2019-04-26)
+
+
+### :star: New Features
+
+* ES modules for browser ([#561](https://github.com/kazupon/vue-i18n/issues/561)) ([c9b9adf](https://github.com/kazupon/vue-i18n/commit/c9b9adf)), closes [#561](https://github.com/kazupon/vue-i18n/issues/561)
+* HTML locale message warning option ([#567](https://github.com/kazupon/vue-i18n/issues/567)) ([4aecf03](https://github.com/kazupon/vue-i18n/commit/4aecf03)), closes [#567](https://github.com/kazupon/vue-i18n/issues/567)
+
+
+
+<a name="8.10.0"></a>
+# [8.10.0](https://github.com/kazupon/vue-i18n/compare/v8.9.0...v8.10.0) (2019-03-28)
+
+
+### :star: New Features
+
+* **number:** i18n-n functional component ([#541](https://github.com/kazupon/vue-i18n/issues/541)) by [@bponomarenko](https://github.com/bponomarenko) ([b33579d](https://github.com/kazupon/vue-i18n/commit/b33579d)), closes [#541](https://github.com/kazupon/vue-i18n/issues/541)
+* **path:** Keypath should parse if sub path contains spaces. ([#533](https://github.com/kazupon/vue-i18n/issues/533)) by [@exoego](https://github.com/exoego) ([640daaf](https://github.com/kazupon/vue-i18n/commit/640daaf)), closes [#533](https://github.com/kazupon/vue-i18n/issues/533)
+
+
+### :zap: Improvements
+
+* **number:** support data fall through in i18n-n ([#545](https://github.com/kazupon/vue-i18n/issues/545)) ([71cadbf](https://github.com/kazupon/vue-i18n/commit/71cadbf)), closes [#545](https://github.com/kazupon/vue-i18n/issues/545)
+
+
+### :pencil: docs
+
+* **vuepress:** translate documents for chinese ([#536](https://github.com/kazupon/vue-i18n/issues/536)) by [@xuhongbo](https://github.com/xuhongbo) ([ccf29f8](https://github.com/kazupon/vue-i18n/commit/ccf29f8)), closes [#536](https://github.com/kazupon/vue-i18n/issues/536) [#531](https://github.com/kazupon/vue-i18n/issues/531) [#1](https://github.com/kazupon/vue-i18n/issues/1) [#533](https://github.com/kazupon/vue-i18n/issues/533) [#540](https://github.com/kazupon/vue-i18n/issues/540) [#541](https://github.com/kazupon/vue-i18n/issues/541) [#1](https://github.com/kazupon/vue-i18n/issues/1) [#2](https://github.com/kazupon/vue-i18n/issues/2)
+
+
+<a name="8.9.0"></a>
+# [8.9.0](https://github.com/kazupon/vue-i18n/compare/v8.8.2...v8.9.0) (2019-03-08)
+
+
+### :bug: Bug Fixes
+
+* **index:** Fix [#515](https://github.com/kazupon/vue-i18n/issues/515) empty string not returning true ([#525](https://github.com/kazupon/vue-i18n/issues/525)) by [@kimuraz](https://github.com/kimuraz) ([396c5ca](https://github.com/kazupon/vue-i18n/commit/396c5ca)), closes [#515](https://github.com/kazupon/vue-i18n/issues/515) [#525](https://github.com/kazupon/vue-i18n/issues/525) [#515](https://github.com/kazupon/vue-i18n/issues/515)
+
+
+### :star: New Features
+
+* **index:** add availableLocales (related issue [#193](https://github.com/kazupon/vue-i18n/issues/193), PR [#528](https://github.com/kazupon/vue-i18n/issues/528)) by [@exoego](https://github.com/exoego) ([8f75b1f](https://github.com/kazupon/vue-i18n/commit/8f75b1f)), closes [#193](https://github.com/kazupon/vue-i18n/issues/193) [#528](https://github.com/kazupon/vue-i18n/issues/528) [#193](https://github.com/kazupon/vue-i18n/issues/193) [#193](https://github.com/kazupon/vue-i18n/issues/193) [#193](https://github.com/kazupon/vue-i18n/issues/193) [#193](https://github.com/kazupon/vue-i18n/issues/193)
+
+
+### :zap: Improvements
+
+* **flowtype:** Fix missing type declarations in flow type ([#529](https://github.com/kazupon/vue-i18n/issues/529)) by [@exoego](https://github.com/exoego) ([4173764](https://github.com/kazupon/vue-i18n/commit/4173764)), closes [#529](https://github.com/kazupon/vue-i18n/issues/529)
+
+
+
+<a name="8.8.2"></a>
+## [8.8.2](https://github.com/kazupon/vue-i18n/compare/v8.8.1...v8.8.2) (2019-02-17)
+
+
+### :bug: Bug Fixes
+
+* **mixin:** fix memory leak ([135058d](https://github.com/kazupon/vue-i18n/commit/135058d)), closes [#514](https://github.com/kazupon/vue-i18n/issues/514)
+
+
+
+<a name="8.8.1"></a>
+## [8.8.1](https://github.com/kazupon/vue-i18n/compare/v8.8.0...v8.8.1) (2019-02-10)
+
+
+### :bug: Bug Fixes
+
+* **index:** fixed [#478](https://github.com/kazupon/vue-i18n/issues/478) ([#518](https://github.com/kazupon/vue-i18n/issues/518)) by [@stroncium](https://github.com/stroncium) ([469edd9](https://github.com/kazupon/vue-i18n/commit/469edd9)), closes [#478](https://github.com/kazupon/vue-i18n/issues/478) [#518](https://github.com/kazupon/vue-i18n/issues/518) [#478](https://github.com/kazupon/vue-i18n/issues/478)
+
+
+### :zap: Improvements
+
+* **flowtype:** update typings ([44e04e7](https://github.com/kazupon/vue-i18n/commit/44e04e7))
+* **typescript:** update typings ([dee35b9](https://github.com/kazupon/vue-i18n/commit/dee35b9))
+
+
+
+<a name="8.8.0"></a>
+# [8.8.0](https://github.com/kazupon/vue-i18n/compare/v8.7.0...v8.8.0) (2019-01-29)
+
+
+### :bug: Bug Fixes
+
+* **index:** fix flat path based key issue ([bed9c39](https://github.com/kazupon/vue-i18n/commit/bed9c39)), closes [#349](https://github.com/kazupon/vue-i18n/issues/349)
+* **mixin:** fix beforeDestroy can not find this.$t ([#500](https://github.com/kazupon/vue-i18n/issues/500)) by [@masongzhi](https://github.com/masongzhi) ([311b8f3](https://github.com/kazupon/vue-i18n/commit/311b8f3)), closes [#500](https://github.com/kazupon/vue-i18n/issues/500)
+
+
+### :zap: Improvements
+
+* **directive:** Fix typo on warning message ([#509](https://github.com/kazupon/vue-i18n/issues/509)) by [@kimuraz](https://github.com/kimuraz) ([e879024](https://github.com/kazupon/vue-i18n/commit/e879024)), closes [#509](https://github.com/kazupon/vue-i18n/issues/509)
+* **index:** silence fallback warnings ([#510](https://github.com/kazupon/vue-i18n/issues/510)) by [@SzNagyMisu](https://github.com/SzNagyMisu) ([ddc0c79](https://github.com/kazupon/vue-i18n/commit/ddc0c79)), closes [#510](https://github.com/kazupon/vue-i18n/issues/510) [#139](https://github.com/kazupon/vue-i18n/issues/139)
+
+
+
+<a name="8.7.0"></a>
+# [8.7.0](https://github.com/kazupon/vue-i18n/compare/v8.6.0...v8.7.0) (2019-01-02)
+
+
+### :zap: Improvements
+
+* **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)
+
+
+
+<a name="8.6.0"></a>
+# [8.6.0](https://github.com/kazupon/vue-i18n/compare/v8.5.0...v8.6.0) (2018-12-25)
+
+
+### :bug: Bug Fixes
+
+* **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)
+
+
+### :zap: Improvements
+
+* **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)
+
+
+
+<a name="8.5.0"></a>
+# [8.5.0](https://github.com/kazupon/vue-i18n/compare/v8.4.0...v8.5.0) (2018-12-17)
+
+
+### :bug: Bug Fixes
+
+* **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)
+
+
+### :zap: Improvements
+
+* **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)
+* **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)
+* **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)
+
+
+
+<a name="8.4.0"></a>
+# [8.4.0](https://github.com/kazupon/vue-i18n/compare/v8.3.2...v8.4.0) (2018-11-30)
+
+
+### :star: New Features
+
+* **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)
+
+
+
+<a name="8.3.2"></a>
+## [8.3.2](https://github.com/kazupon/vue-i18n/compare/v8.3.1...v8.3.2) (2018-11-16)
+
+
+### :chart_with_upwards_trend: Performance Fixes
+
+* **index:** Optimize unnecessary capturing. ([#462](https://github.com/kazupon/vue-i18n/issues/462)) by [@exoego](https://github.com/exoego) ([116845e](https://github.com/kazupon/vue-i18n/commit/116845e)), closes [#462](https://github.com/kazupon/vue-i18n/issues/462)
+
+
+
+<a name="8.3.1"></a>
+## [8.3.1](https://github.com/kazupon/vue-i18n/compare/v8.3.0...v8.3.1) (2018-11-08)
+
+
+### :bug: Bug Fixes
+
+* **directive:** fix cannnot update with v-t when had been changed locale message ([4895a2e](https://github.com/kazupon/vue-i18n/commit/4895a2e)), closes [#450](https://github.com/kazupon/vue-i18n/issues/450)
+* **index:** fix merge bug ([1798490](https://github.com/kazupon/vue-i18n/commit/1798490)), closes [#458](https://github.com/kazupon/vue-i18n/issues/458)
+* **missing:** fix vm argument passing ([dc48099](https://github.com/kazupon/vue-i18n/commit/dc48099)), closes [#453](https://github.com/kazupon/vue-i18n/issues/453)
+
+
+### :zap: Improvements
+
+* Optimize path.js and format.js ([#456](https://github.com/kazupon/vue-i18n/issues/456)) by [@exoego](https://github.com/exoego) ([639453c](https://github.com/kazupon/vue-i18n/commit/639453c)), closes [#456](https://github.com/kazupon/vue-i18n/issues/456)
+
+
+
+<a name="8.3.0"></a>
+# [8.3.0](https://github.com/kazupon/vue-i18n/compare/v8.2.1...v8.3.0) (2018-10-29)
+
+
+### :zap: Improvements
+
+* **pluralization:** Extendable pluralization by [@Raiondesu](https://github.com/Raiondesu) ([bbab90b](https://github.com/kazupon/vue-i18n/commit/bbab90b))
+
+
+
+<a name="8.2.1"></a>
+## [8.2.1](https://github.com/kazupon/vue-i18n/compare/v8.2.0...v8.2.1) (2018-10-15)
+
+
+### :bug: Bug Fixes
+
+* **extend:** fix TypeError: Cannot redefine property: $i18n ([#422](https://github.com/kazupon/vue-i18n/issues/422)) by [@HadiChen](https://github.com/HadiChen) ([cb19082](https://github.com/kazupon/vue-i18n/commit/cb19082)), closes [#422](https://github.com/kazupon/vue-i18n/issues/422)
+
+
+### :zap: Improvements
+
+* **index:** Suppress some warnings in production: smaller min.js and performance gain. ([#441](https://github.com/kazupon/vue-i18n/issues/441)) by @	exoego ([43931f5](https://github.com/kazupon/vue-i18n/commit/43931f5)), closes [#441](https://github.com/kazupon/vue-i18n/issues/441)
+
+
+
+<a name="8.2.0"></a>
+# [8.2.0](https://github.com/kazupon/vue-i18n/compare/v8.1.1...v8.2.0) (2018-10-13)
+
+
+### :bug: Bug Fixes
+
+* **index:** Add warning for circular reference in linked message ([#438](https://github.com/kazupon/vue-i18n/issues/438)) by [@exoego](https://github.com/exoego) ([7583485](https://github.com/kazupon/vue-i18n/commit/7583485)), closes [#438](https://github.com/kazupon/vue-i18n/issues/438)
+
+
+### :zap: Improvements
+
+* **index:** Allow escaping link key like @:(foo.bar). ([#437](https://github.com/kazupon/vue-i18n/issues/437)) by [@exoego](https://github.com/exoego) ([acfc458](https://github.com/kazupon/vue-i18n/commit/acfc458)), closes [#437](https://github.com/kazupon/vue-i18n/issues/437)
+* **index:** Pre-defined named arguments for Pluraization ([#440](https://github.com/kazupon/vue-i18n/issues/440)) by [@exoego](https://github.com/exoego) ([e84f0fb](https://github.com/kazupon/vue-i18n/commit/e84f0fb)), closes [#440](https://github.com/kazupon/vue-i18n/issues/440)
+* **path:** Allow non-ascii chars including numbers. ([#436](https://github.com/kazupon/vue-i18n/issues/436)) by [@exoego](https://github.com/exoego) ([a556c58](https://github.com/kazupon/vue-i18n/commit/a556c58)), closes [#436](https://github.com/kazupon/vue-i18n/issues/436)
+
+
+
+<a name="8.1.1"></a>
+## [8.1.1](https://github.com/kazupon/vue-i18n/compare/v8.1.0...v8.1.1) (2018-10-12)
+
+
+### :bug: Bug Fixes
+
+* **build:** fix rollup building issues ([1a1958a](https://github.com/kazupon/vue-i18n/commit/1a1958a))
+* **format:** Should warn as unknown if named format is not closed. ([#435](https://github.com/kazupon/vue-i18n/issues/435)) by [@exoego](https://github.com/exoego) ([d1f6ed0](https://github.com/kazupon/vue-i18n/commit/d1f6ed0)), closes [#435](https://github.com/kazupon/vue-i18n/issues/435)
+* **install:** fix cannot redfine error ([6d5ec61](https://github.com/kazupon/vue-i18n/commit/6d5ec61))
+
+
+### :zap: Improvements
+
+* **package.json:** tree shaking optimization ([38948c5](https://github.com/kazupon/vue-i18n/commit/38948c5))
+
+
+
+<a name="8.1.0"></a>
+# [8.1.0](https://github.com/kazupon/vue-i18n/compare/v8.0.0...v8.1.0) (2018-09-03)
+
+
+### :bug: Bug Fixes
+
+* **install:** add support for Vue.extend vue-i18n instance ([#420](https://github.com/kazupon/vue-i18n/issues/420)) by [@jaredzhu1993](https://github.com/jaredzhu1993) ([a60ea8b](https://github.com/kazupon/vue-i18n/commit/a60ea8b)), closes [#420](https://github.com/kazupon/vue-i18n/issues/420)
+
+
+### :zap: Improvements
+
+* **warnings:** make warning messages clearer ([#396](https://github.com/kazupon/vue-i18n/issues/396)) by [@kimuraz](https://github.com/kimuraz) ([79eee1b](https://github.com/kazupon/vue-i18n/commit/79eee1b)), closes [#396](https://github.com/kazupon/vue-i18n/issues/396)
+
+
+
+<a name="8.0.0"></a>
+# [8.0.0](https://github.com/kazupon/vue-i18n/compare/v7.8.1...v8.0.0) (2018-06-23)
+
+
+### :boom: Breaking changes
+
+* **extend:** fix this context binding ([aa0e831](https://github.com/kazupon/vue-i18n/commit/aa0e831)), closes [#306](https://github.com/kazupon/vue-i18n/issues/306) [#286](https://github.com/kazupon/vue-i18n/issues/286) [#259](https://github.com/kazupon/vue-i18n/issues/259), revert [#260](https://github.com/kazupon/vue-i18n/issues/260)
+
+Note that you need to guarantee this context equal to component instance in lifecycle methods (e.g. in `data` options, `const $t = this.$t.bind(this)`).
+
+```js
+export default {
+  data () {
+    const $t = this.$t.bind(this)
+    return { msg: $t('msg') }
+  }
+}
+```
+
+see the [API docs](https://kazupon.github.io/vue-i18n/api/)
+
+### :bug: Bug Fixes
+
+* bug(directive): fix guard checking at unbind ([c74888c](https://github.com/kazupon/vue-i18n/commit/c74888c)), closes [#340](https://github.com/kazupon/vue-i18n/issues/340)
+
+
+### NOTE
+
+* extend:
+
+
+
+<a name="7.8.1"></a>
+## [7.8.1](https://github.com/kazupon/vue-i18n/compare/v7.8.0...v7.8.1) (2018-06-18)
+
+
+### :bug: Bug Fixes
+
+* **directive:** fix cannot unbind bug ([105888d](https://github.com/kazupon/vue-i18n/commit/105888d)), closes [#377](https://github.com/kazupon/vue-i18n/issues/377)
+
+
+
+<a name="7.8.0"></a>
+# [7.8.0](https://github.com/kazupon/vue-i18n/compare/v7.7.0...v7.8.0) (2018-06-01)
+
+
+### :zap: Improvements
+
+* **typescript:** add type exportings ([a7cb8da](https://github.com/kazupon/vue-i18n/commit/a7cb8da))
+
+
+
+<a name="7.7.0"></a>
+# [7.7.0](https://github.com/kazupon/vue-i18n/compare/v7.6.0...v7.7.0) (2018-05-20)
+
+
+### :zap: Improvements
+
+* **index:** resource reactivity ([887a137](https://github.com/kazupon/vue-i18n/commit/887a137)), closes [#253](https://github.com/kazupon/vue-i18n/issues/253)
+* **typescript:** Fix typings in components ([#344](https://github.com/kazupon/vue-i18n/issues/344)) by [@Demivan](https://github.com/Demivan) ([2402893](https://github.com/kazupon/vue-i18n/commit/2402893)), closes [#344](https://github.com/kazupon/vue-i18n/issues/344)
+
+
+
+<a name="7.6.0"></a>
+# [7.6.0](https://github.com/kazupon/vue-i18n/compare/v7.5.0...v7.6.0) (2018-03-13)
+
+
+### :zap: Improvements
+
+* **index:** support retunable missing handler ([#256](https://github.com/kazupon/vue-i18n/issues/256)) by [@houd1ni](https://github.com/houd1ni) ([9fbe467](https://github.com/kazupon/vue-i18n/commit/9fbe467))
+* **typescript:** update TranslateResult type interface ([dffc678](https://github.com/kazupon/vue-i18n/commit/dffc678))
+
+
+
+<a name="7.5.0"></a>
+# [7.5.0](https://github.com/kazupon/vue-i18n/compare/v7.4.2...v7.5.0) (2018-03-11)
+
+
+### :star: New Features
+
+* **directive:** Add pluralization feature to directive ([#304](https://github.com/kazupon/vue-i18n/issues/304)) by [@SirLamer](https://github.com/SirLamer) ([8378859](https://github.com/kazupon/vue-i18n/commit/8378859))
+
+
+### :zap: Improvements
+
+* **flow:** update TranslateResult type interface ([59f4658](https://github.com/kazupon/vue-i18n/commit/59f4658))
+* **index:** support object localization ([#311](https://github.com/kazupon/vue-i18n/issues/311)) by [@manniL](https://github.com/manniL) ([99e5006](https://github.com/kazupon/vue-i18n/commit/99e5006))
+* **missing:** Add interpolation values to missing handler ([#308](https://github.com/kazupon/vue-i18n/issues/308)) by [@sebwas](https://github.com/sebwas) ([b912d8a](https://github.com/kazupon/vue-i18n/commit/b912d8a))
+* **numberformat:** Explicit number format options ([#305](https://github.com/kazupon/vue-i18n/issues/305)) by [@bponomarenko](https://github.com/bponomarenko) ([aa07450](https://github.com/kazupon/vue-i18n/commit/aa07450))
+
+
+
+<a name="7.4.2"></a>
+## [7.4.2](https://github.com/kazupon/vue-i18n/compare/v7.4.1...v7.4.2) (2018-02-01)
+
+
+### :zap: Improvements
+
+* **index:** Fixes global auto installation ([#291](https://github.com/kazupon/vue-i18n/issues/291)) by [@emileber](https://github.com/emileber) ([2f016ff](https://github.com/kazupon/vue-i18n/commit/2f016ff)), closes [#291](https://github.com/kazupon/vue-i18n/issues/291)
+
+
+
+<a name="7.4.1"></a>
+## [7.4.1](https://github.com/kazupon/vue-i18n/compare/v7.4.0...v7.4.1) (2018-01-25)
+
+
+### :bug: Bug Fixes
+
+* fix cannot react ([2a8ea1c](https://github.com/kazupon/vue-i18n/commit/2a8ea1c)), closes [#261](https://github.com/kazupon/vue-i18n/issues/261)
+
+
+### :zap: Improvements
+
+* **formatter:** interpolate messages without values ([#282](https://github.com/kazupon/vue-i18n/issues/282)) by [@cb8](https://github.com/cb8) ([b792ce2](https://github.com/kazupon/vue-i18n/commit/b792ce2))
+
+
+
+<a name="7.4.0"></a>
+# [7.4.0](https://github.com/kazupon/vue-i18n/compare/v7.3.4...v7.4.0) (2018-01-10)
+
+
+### :star: New Features
+
+* **typescript:** Allow module augmentation ([#273](https://github.com/kazupon/vue-i18n/issues/273)) by [@CKGrafico](https://github.com/CKGrafico) ([4371344](https://github.com/kazupon/vue-i18n/commit/4371344))
+
+
+
+<a name="7.3.4"></a>
+## [7.3.4](https://github.com/kazupon/vue-i18n/compare/v7.3.3...v7.3.4) (2018-01-07)
+
+
+### :bug: Bug Fixes
+
+* **formatter:** Inherit formatter ([#269](https://github.com/kazupon/vue-i18n/issues/269)) by [@podkot](https://github.com/podkot) ([26a33ad](https://github.com/kazupon/vue-i18n/commit/26a33ad))
+
+
+
+<a name="7.3.3"></a>
+## [7.3.3](https://github.com/kazupon/vue-i18n/compare/v7.3.2...v7.3.3) (2017-12-19)
+
+
+### :bug: Bug Fixes
+
+* **extend:** Fix this not found [#259](https://github.com/kazupon/vue-i18n/issues/259) ([#260](https://github.com/kazupon/vue-i18n/issues/260)) by [@lzxb](https://github.com/lzxb) ([c29007e](https://github.com/kazupon/vue-i18n/commit/c29007e)), closes [#259](https://github.com/kazupon/vue-i18n/issues/259) [#260](https://github.com/kazupon/vue-i18n/issues/260)
+* **types:** fix using old export ([#263](https://github.com/kazupon/vue-i18n/issues/263)) by [@jmigual](https://github.com/jmigual) ([b295fee](https://github.com/kazupon/vue-i18n/commit/b295fee)), closes [#263](https://github.com/kazupon/vue-i18n/issues/263)
+
+
+<a name="7.3.2"></a>
+## [7.3.2](https://github.com/kazupon/vue-i18n/compare/v7.3.1...v7.3.2) (2017-10-19)
+
+
+### :zap: Improvements
+
+* **typescript:** fix import problem of vue2.5 because of the types update ([#238](https://github.com/kazupon/vue-i18n/issues/238)) by [@peterchealse](https://github.com/peterchealse) ([cb98347](https://github.com/kazupon/vue-i18n/commit/cb98347)), closes [#238](https://github.com/kazupon/vue-i18n/issues/238)
+
+
+
+<a name="7.3.1"></a>
+## [7.3.1](https://github.com/kazupon/vue-i18n/compare/v7.3.0...v7.3.1) (2017-10-04)
+
+
+### :bug: Bug Fixes
+
+* **directive:** fix cannot locale reactivity ([e1fc12e](https://github.com/kazupon/vue-i18n/commit/e1fc12e)), closes [#227](https://github.com/kazupon/vue-i18n/issues/227)
+
+
+
+<a name="7.3.0"></a>
+# [7.3.0](https://github.com/kazupon/vue-i18n/compare/v7.2.0...v7.3.0) (2017-09-22)
+
+
+### :star: New Features
+
+* **directives:** support v-t custom directive (welcome back!) ([af9a2e7](https://github.com/kazupon/vue-i18n/commit/af9a2e7))
+
+
+### :up: Updates
+
+* **typing:** fix flowtype ([fa06f44](https://github.com/kazupon/vue-i18n/commit/fa06f44))
+
+
+
+<a name="7.2.0"></a>
+# [7.2.0](https://github.com/kazupon/vue-i18n/compare/v7.1.2...v7.2.0) (2017-08-28)
+
+
+### :star: New Features
+
+* **interpolation:** list formatting refactor and places/place feature ([#218](https://github.com/kazupon/vue-i18n/issues/218)) by [@myst729](https://github.com/myst729) ([0f0f3ff](https://github.com/kazupon/vue-i18n/commit/0f0f3ff))
+
+
+
+<a name="7.1.2"></a>
+## [7.1.2](https://github.com/kazupon/vue-i18n/compare/v7.1.1...v7.1.2) (2017-08-25)
+
+
+### :zap: Improvements
+
+* **interpolation:** skip non-element VNode in interpolation ([#211](https://github.com/kazupon/vue-i18n/issues/211)) by [@myst729](https://github.com/myst729) ([6be1756](https://github.com/kazupon/vue-i18n/commit/6be1756))
+
+
+
+<a name="7.1.1"></a>
+## [7.1.1](https://github.com/kazupon/vue-i18n/compare/v7.1.0...v7.1.1) (2017-08-03)
+
+
+### :bug: Bug Fixes
+
+* **mixin:** fix cannot setup VueI18n instance ([13585a4](https://github.com/kazupon/vue-i18n/commit/13585a4)), closes [#203](https://github.com/kazupon/vue-i18n/issues/203)
+
+
+
+<a name="7.1.0"></a>
+# [7.1.0](https://github.com/kazupon/vue-i18n/compare/v7.0.5...v7.1.0) (2017-07-30)
+
+
+### :zap: Improvements
+
+* **custom-block:** support multiple custom blocks ([ab955a5](https://github.com/kazupon/vue-i18n/commit/ab955a5)), closes [#189](https://github.com/kazupon/vue-i18n/issues/189)
+
+
+
+<a name="7.0.5"></a>
+## [7.0.5](https://github.com/kazupon/vue-i18n/compare/v7.0.4...v7.0.5) (2017-07-08)
+
+
+### :bug: Bug Fixes
+
+* **format:** fix cannot collectly parse percent ([fc71eda](https://github.com/kazupon/vue-i18n/commit/fc71eda)), closes [#191](https://github.com/kazupon/vue-i18n/issues/191)
+
+
+
+<a name="7.0.4"></a>
+## [7.0.4](https://github.com/kazupon/vue-i18n/compare/v7.0.3...v7.0.4) (2017-07-01)
+
+
+### :bug: Bug Fixes
+
+* **link:** fix ie traverse custom Array.prototype method ([#188](https://github.com/kazupon/vue-i18n/issues/188)) by [@632781460](https://github.com/632781460) ([d3b308b](https://github.com/kazupon/vue-i18n/commit/d3b308b)), closes [#188](https://github.com/kazupon/vue-i18n/issues/188)
+
+
+### :chart_with_upwards_trend: Performance Fixes
+
+* fix blocking at beforeDestroy ([570b215](https://github.com/kazupon/vue-i18n/commit/570b215)), closes [#187](https://github.com/kazupon/vue-i18n/issues/187)
+
+
+
+<a name="7.0.3"></a>
+## [7.0.3](https://github.com/kazupon/vue-i18n/compare/v7.0.2...v7.0.3) (2017-06-13)
+
+
+### :bug: Bug Fixes
+
+* **fallback:** fix cannot fallabck localization ([694e6f2](https://github.com/kazupon/vue-i18n/commit/694e6f2)), closes [#176](https://github.com/kazupon/vue-i18n/issues/176)
+* **fallback:** fix fallback locale issue ([d9ceddc](https://github.com/kazupon/vue-i18n/commit/d9ceddc)), closes [#174](https://github.com/kazupon/vue-i18n/issues/174)
+* **linked:** fix cannot fallback linked localization ([0c572f3](https://github.com/kazupon/vue-i18n/commit/0c572f3)), closes [#172](https://github.com/kazupon/vue-i18n/issues/172)
+
+
+
+<a name="7.0.2"></a>
+## [7.0.2](https://github.com/kazupon/vue-i18n/compare/v7.0.1...v7.0.2) (2017-06-10)
+
+
+### :bug: Bug Fixes
+
+* **sfc:** fix cannot parse custom block locale messages ([32eb3a7](https://github.com/kazupon/vue-i18n/commit/32eb3a7)), closes [#173](https://github.com/kazupon/vue-i18n/issues/173)
+
+
+
+<a name="7.0.1"></a>
+## [7.0.1](https://github.com/kazupon/vue-i18n/compare/v7.0.0...v7.0.1) (2017-06-04)
+
+
+### :bug: Bug Fixes
+
+* fix cannat single file component translation ([687d406](https://github.com/kazupon/vue-i18n/commit/687d406)), closes [#169](https://github.com/kazupon/vue-i18n/issues/169)
+* fix cannnot resolve linked localization with component interpolation ([c973619](https://github.com/kazupon/vue-i18n/commit/c973619)), closes [#171](https://github.com/kazupon/vue-i18n/issues/171)
+* fix datetime and number fallback localization ([be9e1bd](https://github.com/kazupon/vue-i18n/commit/be9e1bd)), closes [#168](https://github.com/kazupon/vue-i18n/issues/168)
+* fix linked translation with using hyphen or underscore keypath ([6e9f151](https://github.com/kazupon/vue-i18n/commit/6e9f151)), closes [#170](https://github.com/kazupon/vue-i18n/issues/170)
+
+
+<a name="7.0.0"></a>
+# [7.0.0](https://github.com/kazupon/vue-i18n/compare/v7.0.0-rc.1...v7.0.0) (2017-05-29)
+
+:tada: :tada: :tada:
+
+See the [docs](https://kazupon.github.io/vue-i18n/en/)
+
+
+### :star: New Features
+
+* **datetime localization:**
+    * [documentation](https://github.com/kazupon/vue-i18n/blob/dev/gitbook/en/datetime.md)
+    * [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/datetime)
+* **number localization:**
+    * [documentation](https://github.com/kazupon/vue-i18n/blob/dev/gitbook/en/number.md)
+    * [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/number)
+* **component interpolation:**
+    * [documentation](https://github.com/kazupon/vue-i18n/blob/dev/gitbook/en/interpolation.md)
+    * [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/interpolation)
+* **typescript:**
+    * [type definitions](https://github.com/kazupon/vue-i18n/blob/dev/types/index.d.ts)
+
+
+### :chart_with_upwards_trend: Performance Fixes
+
+* fix translation performance issue ([6032a51](https://github.com/kazupon/vue-i18n/commit/6032a51))
+
+
+### :zap: Improvements
+
+* **path:** tweak for ssr
+
+
+### :boom: Breaking changes
+
+* **format:** re-impelement formatter
+* **formatter:** change method nam
+* **flowtype:** fix locale message related type changing and remove underscore type
+
+
+### :bug: Bug Fixes
+
+* **examples:** fix ssr demo ([059034f](https://github.com/kazupon/vue-i18n/commit/059034f))
+* **pluralization:** fix default choice ([240cfed](https://github.com/kazupon/vue-i18n/commit/240cfed))
+
+
+<a name="7.0.0-rc.1"></a>
+# [7.0.0-rc.1](https://github.com/kazupon/vue-i18n/compare/v7.0.0-beta.4...v7.0.0-rc.1) (2017-05-26)
+
+
+### :chart_with_upwards_trend: Performance Fixes
+
+* fix translation performance issue ([6032a51](https://github.com/kazupon/vue-i18n/commit/6032a51)), closes [#165](https://github.com/kazupon/vue-i18n/issues/165)
+
+
+### :up: Updates
+
+* **flowtype:** remove unneccesary type ([eb60156](https://github.com/kazupon/vue-i18n/commit/eb60156))
+
+
+
+<a name="7.0.0-beta.4"></a>
+# [7.0.0-beta.4](https://github.com/kazupon/vue-i18n/compare/v7.0.0-beta.3...v7.0.0-beta.4) (2017-05-23)
+
+
+### :bug: Bug Fixes
+
+* **pluralization:** fix default choice ([240cfed](https://github.com/kazupon/vue-i18n/commit/240cfed)), closes [#164](https://github.com/kazupon/vue-i18n/issues/164)
+
+
+
+<a name="7.0.0-beta.3"></a>
+# [7.0.0-beta.3](https://github.com/kazupon/vue-i18n/compare/v7.0.0-beta.2...v7.0.0-beta.3) (2017-05-15)
+
+### :up: Updates
+
+* bring back from bug fix ([95be4ea](https://github.com/kazupon/vue-i18n/commit/95be4ea))
+
+
+<a name="7.0.0-beta.2"></a>
+# [7.0.0-beta.2](https://github.com/kazupon/vue-i18n/compare/v7.0.0-beta.1...v7.0.0-beta.2) (2017-05-14)
+
+
+### :zap: Improvements
+
+* **path:** tweak for ssr ([eb21921](https://github.com/kazupon/vue-i18n/commit/eb21921))
+* **typescript:** change custom formatter method name ([c5f043f](https://github.com/kazupon/vue-i18n/commit/c5f043f))
+
+
+
+<a name="7.0.0-beta.1"></a>
+# [7.0.0-beta.1](https://github.com/kazupon/vue-i18n/compare/v6.1.1...v7.0.0-beta.1) (2017-05-11)
+
+### :star: New Features
+
+* **datetime localization:** add datetime localization ([3282075](https://github.com/kazupon/vue-i18n/commit/3282075))
+    * [documentation](https://github.com/kazupon/vue-i18n/blob/dev/gitbook/en/datetime.md)
+    * [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/datetime)
+* **number localization:** add number localization ([87ee7b3](https://github.com/kazupon/vue-i18n/commit/87ee7b3))
+    * [documentation](https://github.com/kazupon/vue-i18n/blob/dev/gitbook/en/number.md)
+    * [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/number)
+* **component interpolation:** ([23f7d34](https://github.com/kazupon/vue-i18n/commit/23f7d34)), closes [#145](https://github.com/kazupon/vue-i18n/issues/145) [#144](https://github.com/kazupon/vue-i18n/issues/144) [#37](https://github.com/kazupon/vue-i18n/issues/37)
+    * [documentation](https://github.com/kazupon/vue-i18n/blob/dev/gitbook/en/interpolation.md)
+    * [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/interpolation)
+* **typescript:** add TypeScript type definitions ([#161](https://github.com/kazupon/vue-i18n/issues/161)) by [@aicest](https://github.com/aicest) ([61cebca](https://github.com/kazupon/vue-i18n/commit/61cebca))
+    * [type definitions](https://github.com/kazupon/vue-i18n/blob/dev/types/index.d.ts)
+
+
+### :boom: Breaking changes
+
+* **format:** re-impelement formatter ([a8c046d](https://github.com/kazupon/vue-i18n/commit/a8c046d))
+* **formatter:** change method name ([6eed51c](https://github.com/kazupon/vue-i18n/commit/6eed51c))
+* **flowtype:** fix locale message related type changing ([c30d576](https://github.com/kazupon/vue-i18n/commit/c30d576))
+
+
+### :bug: Bug Fixes
+
+* **examples:** fix ssr demo ([059034f](https://github.com/kazupon/vue-i18n/commit/059034f)), closes [#151](https://github.com/kazupon/vue-i18n/issues/151)
+
+
+<a name="6.1.3"></a>
+## [6.1.3](https://github.com/kazupon/vue-i18n/compare/v6.1.1...v6.1.3) (2017-05-15)
+
+
+### :bug: Bug Fixes
+
+* fix memory leaks ([95be4ea](https://github.com/kazupon/vue-i18n/commit/95be4ea)), closes [#162](https://github.com/kazupon/vue-i18n/issues/162)
+
+
+
+<a name="6.1.2"></a>
+## [6.1.2](https://github.com/kazupon/vue-i18n/compare/v6.1.1...v6.1.2) (2017-05-15)
+
+
+<a name="6.1.1"></a>
+## [6.1.1](https://github.com/kazupon/vue-i18n/compare/v6.1.0...v6.1.1) (2017-04-19)
+
+
+### :bug: Bug Fixes
+
+* **te:** Fix `te()` that always uses `this.locale`, even when `locale` supplied ([#147](https://github.com/kazupon/vue-i18n/issues/147)) by [@aicest](https://github.com/aicest) ([bf15eeb](https://github.com/kazupon/vue-i18n/commit/bf15eeb)), closes [#147](https://github.com/kazupon/vue-i18n/issues/147)
+
+
+
+<a name="6.1.0"></a>
+# [6.1.0](https://github.com/kazupon/vue-i18n/compare/v6.0.0...v6.1.0) (2017-04-14)
+
+
+### :star: New Features
+
+* **api:** add 'mergeLocaleMessage' method ([ef21621](https://github.com/kazupon/vue-i18n/commit/ef21621)), closes [#131](https://github.com/kazupon/vue-i18n/issues/131)
+* **silent:** add silent translation missing option ([29b3a17](https://github.com/kazupon/vue-i18n/commit/29b3a17)), closes [#139](https://github.com/kazupon/vue-i18n/issues/139)
+
+
+### :zap: Improvements
+
+* change to method from computed property ([9135a59](https://github.com/kazupon/vue-i18n/commit/9135a59)), closes [#141](https://github.com/kazupon/vue-i18n/issues/141)
+
+
+
+<a name="6.0.0"></a>
+# [6.0.0](https://github.com/kazupon/vue-i18n/compare/v6.0.0-beta.1...v6.0.0) (2017-04-05)
+
+:tada: :tada: :tada:
+
+See the [docs](https://kazupon.github.io/vue-i18n/en/)
+
+### :zap: Improvements
+
+- Server-Side Rendering: [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/ssr)
+- Custom formatter: [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/formatting/custom)
+
+
+### :star: NEW Features
+
+- Single File Components: [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/sfc)
+
+
+### :boom: Breaking changes
+
+- API
+- Dynamic locale <sup>DEPRECATED</sup>
+
+
+<a name="6.0.0-beta.1"></a>
+# [6.0.0-beta.1](https://github.com/kazupon/vue-i18n/compare/v6.0.0-alpha.6...v6.0.0-beta.1) (2017-03-22)
+
+
+### :boom: Breaking changes
+
+* change `fallbackRoot` and `sync` option default `true` value ([0890b44](https://github.com/kazupon/vue-i18n/commit/0890b44))
+* remove messages settter, and add getLocaleMessage API ([0f0914d](https://github.com/kazupon/vue-i18n/commit/0f0914d))
+
+
+### :bug: Bug Fixes
+
+* **mixin:** fix computed props errors ([a6b7e37](https://github.com/kazupon/vue-i18n/commit/a6b7e37))
+
+
+### :up: Updates
+
+* **flowtype:** argument names ([cf14425](https://github.com/kazupon/vue-i18n/commit/cf14425))
+
+
+### :zap: Improvements
+
+* **fallbackLocale:** support reactivity ([ed758be](https://github.com/kazupon/vue-i18n/commit/ed758be))
+* **warn:** suppress warning messages for production ([6e417d2](https://github.com/kazupon/vue-i18n/commit/6e417d2))
+
+
+
+<a name="6.0.0-alpha.6"></a>
+# [6.0.0-alpha.6](https://github.com/kazupon/vue-i18n/compare/v6.0.0-alpha.5...v6.0.0-alpha.6) (2017-03-16)
+
+
+### :star: New Features
+
+* add 'setLocaleMessage' API ([8b71eda](https://github.com/kazupon/vue-i18n/commit/8b71eda))
+
+
+
+<a name="6.0.0-alpha.5"></a>
+# [6.0.0-alpha.5](https://github.com/kazupon/vue-i18n/compare/v6.0.0-alpha.3...v6.0.0-alpha.5) (2017-03-11)
+
+
+### :bug: Bug Fixes
+
+* **mixin:** fix cannot create VueI18n instance error for minify production ([7eeb29f](https://github.com/kazupon/vue-i18n/commit/7eeb29f))
+
+
+
+<a name="6.0.0-alpha.4"></a>
+# [6.0.0-alpha.4](https://github.com/kazupon/vue-i18n/compare/v6.0.0-alpha.3...v6.0.0-alpha.4) (2017-03-11)
+
+
+
+<a name="6.0.0-alpha.3"></a>
+# [6.0.0-alpha.3](https://github.com/kazupon/vue-i18n/compare/v6.0.0-alpha.2...v6.0.0-alpha.3) (2017-03-08)
+
+
+### :star: New Features
+
+* add `sync` option ([5c46c07](https://github.com/kazupon/vue-i18n/commit/5c46c07))
+
+
+### :zap: Improvements
+
+* **mixin:** add error throwings and a warning ([0e4ac39](https://github.com/kazupon/vue-i18n/commit/0e4ac39))
+
+
+
+<a name="6.0.0-alpha.2"></a>
+# [6.0.0-alpha.2](https://github.com/kazupon/vue-i18n/compare/v6.0.0-alpha.1...v6.0.0-alpha.2) (2017-02-27)
+
+
+### :zap: Improvements
+
+* **mixin:** release i18n instance ([cc362a3](https://github.com/kazupon/vue-i18n/commit/cc362a3))
+* **vue:** support vue 2.2 ([5e7bf5e](https://github.com/kazupon/vue-i18n/commit/5e7bf5e))
+
+
+
+<a name="6.0.0-alpha.1"></a>
+# [6.0.0-alpha.1](https://github.com/kazupon/vue-i18n/compare/v5.0.2...v6.0.0-alpha.1) (2017-02-23)
+
+This is the first release of 6.0.
+In this version, we are some big breaking changes.
+
+- Recommended for: experiments, prototypes, upgrading small, non-critical apps
+- **NOT** recommended for: production use, upgrading production apps
+
+:warning: Documentation still needs to be worked on. And also, we might change some APIs and features.
+
+In the examples, please refer to this [examples](https://github.com/kazupon/vue-i18n/tree/dev/examples) directory.
+
+
+## Improvements
+- Server-Side Rendering: [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/formatting/custom)
+- Custom formatter: [example](https://github.com/kazupon/vue-i18n/tree/dev/examples/ssr)
+
+## Features
+- Formatting <sup>support</sup>
+- Pluralization <sup>support</sup>
+- Locale and KeyPath Syntax <sup>support</sup>
+- Linked translation <sup>support</sup>
+- Fallback translation <sup>support</sup>
+- Component locale <sup>support</sup>
+- Dynamic locale <sup>DEPRECATED</sup>
+- Hot reload <sup>support</sup>
+
+## API
+
+### Global Config
+- Vue.config.lang <sup>DEPRECATED, use VueI18n constructor `locale` option, or VueI18n#locale</sup>
+- Vue.config.fallbackLang <sup>DEPRECATED, use VueI18n constructor `fallbackLocale` option, or VueI18n#fallbackLocale</sup>
+- Vue.config.missingHandler <sup>DEPRECATED, use VueI18n constructor `missing` option, or VueI18n#missing</sup>
+- Vue.config.i18nFormatter <sup>DEPRECATED, use VueI18n constructor `formatter` option, or VueI18n#formatter</sup>
+
+### Global Method
+- Vue.locale <sup>DEPRECATED, use VueI18n constructor `messages` option, or VueI18n#messages</sup>
+- Vue.t <sup>DEPRECATED, use VueI18n#t</sup>
+- Vue.tc <sup>DEPRECATED, use VueI18n#tc</sup>
+- Vue.te <sup>DEPRECATED, use VueI18n#te</sup>
+
+### Constructor Options
+- locales <sup>DEPRECATED, use `messages` of `i18n` option (e.g `{ i18n: { messaes: ... } }`)</sup>
+
+### Instance Properties
+- $lang <sup>DEPRECATED, use `locale` of Vue instance property `$i18n` (e.g `vm.$i18n.locale = 'en'`)
+
+### VueI18n class <sup>NEW</sup>
+- constructor options: See the [`I18nOptions` type](https://github.com/kazupon/vue-i18n/blob/dev/decls/i18n.js#L7-L15) of flowtype.
+- methods / properties: See the [`I18n` interface definition](https://github.com/kazupon/vue-i18n/blob/dev/decls/i18n.js#L17-L33) of flowtype.
+
+
+<a name="5.0.2"></a>
+## [5.0.2](https://github.com/kazupon/vue-i18n/compare/v5.0.1...v5.0.2) (2017-02-18)
+
+
+### :zap: Improvements
+
+* **npm:** revert node >= 6.0 engine restriction ([#110](https://github.com/kazupon/vue-i18n/issues/110)) by [@syxolk](https://github.com/syxolk) ([92b1bd1](https://github.com/kazupon/vue-i18n/commit/92b1bd1)), closes [#109](https://github.com/kazupon/vue-i18n/issues/109)
+
+
+
+<a name="5.0.1"></a>
+## [5.0.1](https://github.com/kazupon/vue-i18n/compare/v5.0.0...v5.0.1) (2017-02-16)
+
+
+### :zap: Improvements
+
+* **asset:** update locale reactivity setting ([b42fd9a](https://github.com/kazupon/vue-i18n/commit/b42fd9a))
+
+
+
+<a name="5.0.0"></a>
+# [5.0.0](https://github.com/kazupon/vue-i18n/compare/v4.10.0...v5.0.0) (2017-02-04)
+
+
+### :boom: Breaking changes
+
+* drop vue 1.0 supporting ([4da26cf](https://github.com/kazupon/vue-i18n/commit/4da26cf)), closes [#105](https://github.com/kazupon/vue-i18n/issues/105)
+
+
+
+<a name="4.10.0"></a>
+# [4.10.0](https://github.com/kazupon/vue-i18n/compare/v4.9.0...v4.10.0) (2017-01-01)
+
+
+### :star: New Features
+
+* `$lang` property for all component ([#99](https://github.com/kazupon/vue-i18n/issues/99)) by [@albert](https://github.com/albert)-zhang ([5ed69f8](https://github.com/kazupon/vue-i18n/commit/5ed69f8))
+
+
+### :up: Updates
+
+* **override:** change langVM keeping variable name ([3ec1bb2](https://github.com/kazupon/vue-i18n/commit/3ec1bb2))
+
+
+
+<a name="4.9.0"></a>
+# [4.9.0](https://github.com/kazupon/vue-i18n/compare/v4.8.0...v4.9.0) (2016-12-17)
+
+
+### :bug: Bug Fixes
+
+* **path:** fix nested key translation ([e15ead4](https://github.com/kazupon/vue-i18n/commit/e15ead4)), closes [#97](https://github.com/kazupon/vue-i18n/issues/97)
+
+
+### :star: New Features
+
+* add globally locale checking ([4cac8b9](https://github.com/kazupon/vue-i18n/commit/4cac8b9))
+* locale checking ([#98](https://github.com/kazupon/vue-i18n/issues/98)) by [@long](https://github.com/long)-long-float ([0bc0a6b](https://github.com/kazupon/vue-i18n/commit/0bc0a6b))
+
+
+<a name="4.8.0"></a>
+# [4.8.0](https://github.com/kazupon/vue-i18n/compare/v4.7.4...v4.8.0) (2016-12-08)
+
+
+### :zap: Improvements
+
+* **extend:** disable no translation warning when set missingHandler ([168a97c](https://github.com/kazupon/vue-i18n/commit/168a97c)), closes [#96](https://github.com/kazupon/vue-i18n/issues/96)
+
+
+
+<a name="4.7.4"></a>
+## [4.7.4](https://github.com/kazupon/vue-i18n/compare/v4.7.3...v4.7.4) (2016-11-29)
+
+
+### :bug: Bug Fixes
+
+* **extend:** fix interpolate error [@tariq86](https://github.com/tariq86) ([5f24e17](https://github.com/kazupon/vue-i18n/commit/5f24e17))
+
+
+
+<a name="4.7.3"></a>
+## [4.7.3](https://github.com/kazupon/vue-i18n/compare/v4.7.2...v4.7.3) (2016-11-24)
+
+
+### :bug: Bug Fixes
+
+* **extend:** fix array local ([35c268a](https://github.com/kazupon/vue-i18n/commit/35c268a)), closes [#91](https://github.com/kazupon/vue-i18n/issues/91) [#59](https://github.com/kazupon/vue-i18n/issues/59)
+
+
+
+<a name="4.7.2"></a>
+## [4.7.2](https://github.com/kazupon/vue-i18n/compare/v4.7.1...v4.7.2) (2016-11-19)
+
+
+### :bug: Bug Fixes
+
+* **observer:** fix dep undefined error ([#88](https://github.com/kazupon/vue-i18n/issues/88)) by [@fandaa](https://github.com/fandaa) ([724974e](https://github.com/kazupon/vue-i18n/commit/724974e)), closes [#88](https://github.com/kazupon/vue-i18n/issues/88)
+
+
+### :zap: Improvements
+
+* **extend:** support translate empty string ([#86](https://github.com/kazupon/vue-i18n/issues/86)) by [@QingWei](https://github.com/QingWei)-Li ([8e6d154](https://github.com/kazupon/vue-i18n/commit/8e6d154))
+
+
+
+<a name="4.7.1"></a>
+## [4.7.1](https://github.com/kazupon/vue-i18n/compare/v4.7.0...v4.7.1) (2016-10-29)
+
+
+### :bug: Bug Fixes
+
+* **interpolate:** named formatting: use name if value is missing ([#77](https://github.com/kazupon/vue-i18n/issues/77)) by [@SebastianS90](https://github.com/SebastianS90) ([a0cc343](https://github.com/kazupon/vue-i18n/commit/a0cc343))
+
+
+### :zap: Improvements
+
+* **named:** using default use nmae when value is missing ([c34e8f1](https://github.com/kazupon/vue-i18n/commit/c34e8f1))
+
+
+
+<a name="4.7.0"></a>
+# [4.7.0](https://github.com/kazupon/vue-i18n/compare/v4.6.0...v4.7.0) (2016-10-28)
+
+
+### :star: New Features
+
+* hot reloading ([#71](https://github.com/kazupon/vue-i18n/issues/71)) by [@gglnx](https://github.com/gglnx) ([7bb94ac](https://github.com/kazupon/vue-i18n/commit/7bb94ac))
+
+
+### :zap: Improvements
+
+* **pluralization:** zero choice ([#70](https://github.com/kazupon/vue-i18n/issues/70)) by [@sebwas](https://github.com/sebwas) ([5f0004f](https://github.com/kazupon/vue-i18n/commit/5f0004f))
+
+
+
+<a name="4.6.0"></a>
+# [4.6.0](https://github.com/kazupon/vue-i18n/compare/v4.5.0...v4.6.0) (2016-09-24)
+
+
+### :star: New Features
+
+* **config:** custom message formatter ([#57](https://github.com/kazupon/vue-i18n/issues/57)) by [@jvmccarthy](https://github.com/jvmccarthy) ([2748eb4](https://github.com/kazupon/vue-i18n/commit/2748eb4))
+
+
+
+<a name="4.5.0"></a>
+# [4.5.0](https://github.com/kazupon/vue-i18n/compare/v4.4.1...v4.5.0) (2016-09-15)
+
+
+### :star: New Features
+
+* **config:** translation miss capturing configration ([aca0ed6](https://github.com/kazupon/vue-i18n/commit/aca0ed6)), closes [#54](https://github.com/kazupon/vue-i18n/issues/54)
+
+
+
+<a name="4.4.1"></a>
+## [4.4.1](https://github.com/kazupon/vue-i18n/compare/v4.4.0...v4.4.1) (2016-09-10)
+
+
+### :zap: Improvements
+
+* **translate:** support hyphenated key ([#52](https://github.com/kazupon/vue-i18n/issues/52)) by [@tariq86](https://github.com/tariq86) ([a40acfd](https://github.com/kazupon/vue-i18n/commit/a40acfd))
+
+
+
+<a name="4.4.0"></a>
+# [4.4.0](https://github.com/kazupon/vue-i18n/compare/v4.3.1...v4.4.0) (2016-08-29)
+
+
+### :star: New Features
+
+* add linked translations ([#50](https://github.com/kazupon/vue-i18n/issues/50)) by [@mmochetti](https://github.com/mmochetti) ([f7ae073](https://github.com/kazupon/vue-i18n/commit/f7ae073))
+
+
+
+<a name="4.3.1"></a>
+## [4.3.1](https://github.com/kazupon/vue-i18n/compare/v4.3.0...v4.3.1) (2016-08-26)
+
+
+### :bug: Bug Fixes
+
+* **npm:** fix installing bug ([57e66aa](https://github.com/kazupon/vue-i18n/commit/57e66aa)), closes [#46](https://github.com/kazupon/vue-i18n/issues/46)
+
+
+
+<a name="4.3.0"></a>
+# [4.3.0](https://github.com/kazupon/vue-i18n/compare/v4.2.3...v4.3.0) (2016-08-26)
+
+
+### :star: New Features
+
+* add pluralization ([#44](https://github.com/kazupon/vue-i18n/issues/44)) by [@mmochetti](https://github.com/mmochetti) ([b5b84d8](https://github.com/kazupon/vue-i18n/commit/b5b84d8))
+
+
+
+<a name="4.2.3"></a>
+## [4.2.3](https://github.com/kazupon/vue-i18n/compare/v4.2.2...v4.2.3) (2016-08-23)
+
+
+### :chart_with_upwards_trend: Performance Fixes
+
+* improve re-rendering cost when change the lang ([0707338](https://github.com/kazupon/vue-i18n/commit/0707338))
+
+
+
+<a name="4.2.2"></a>
+## [4.2.2](https://github.com/kazupon/vue-i18n/compare/v4.2.1...v4.2.2) (2016-08-15)
+
+
+### :bug: Bug Fixes
+
+* **path:** fix array path syntax error ([bc9dbee](https://github.com/kazupon/vue-i18n/commit/bc9dbee)), closes [#42](https://github.com/kazupon/vue-i18n/issues/42) [#43](https://github.com/kazupon/vue-i18n/issues/43)
+
+
+
+<a name="4.2.1"></a>
+## [4.2.1](https://github.com/kazupon/vue-i18n/compare/v4.2.0...v4.2.1) (2016-08-13)
+
+
+### :zap: Improvements
+
+* **translate:** fallback translation warning ([5f6b271](https://github.com/kazupon/vue-i18n/commit/5f6b271))
+
+
+
+<a name="4.2.0"></a>
+# [4.2.0](https://github.com/kazupon/vue-i18n/compare/v4.1.0...v4.2.0) (2016-08-12)
+
+
+### :chart_with_upwards_trend: Performance Fixes
+
+* **format:** use hasOwn function of Vue.util ([a8a19a0](https://github.com/kazupon/vue-i18n/commit/a8a19a0))
+
+
+### :star: New Features
+
+* **fallback:** add fallback translation feature ([1d1f0f2](https://github.com/kazupon/vue-i18n/commit/1d1f0f2)), closes [#36](https://github.com/kazupon/vue-i18n/issues/36)
+
+
+
+<a name="4.1.0"></a>
+# [4.1.0](https://github.com/kazupon/vue-i18n/compare/v4.0.1...v4.1.0) (2016-07-25)
+
+
+### :bug: Bug Fixes
+
+* **util:** fixed isArray reference errors ([0c6f6a0](https://github.com/kazupon/vue-i18n/commit/0c6f6a0))
+
+
+### :star: New Features
+
+* support vue 2.0.0.beta later ([0e1d2f7](https://github.com/kazupon/vue-i18n/commit/0e1d2f7))
+
+
+
+<a name="4.0.1"></a>
+## [4.0.1](https://github.com/kazupon/vue-i18n/compare/v4.0.0...v4.0.1) (2016-06-06)
+
+
+### :bug: Bug Fixes
+
+* **translate:** fix underscore named argument translate issue ([eeaf936](https://github.com/kazupon/vue-i18n/commit/eeaf936))
+
+
+
+<a name="4.0.0"></a>
+# [4.0.0](https://github.com/kazupon/vue-i18n/compare/v3.1.1...v4.0.0) (2016-05-10)
+
+
+### :zap: Improvements
+
+* support vue 2.0-pre-alpha ([f6517bc](https://github.com/kazupon/vue-i18n/commit/f6517bc))
+
+
+
+<a name="3.1.1"></a>
+## [3.1.1](https://github.com/kazupon/vue-i18n/compare/v3.1.0...v3.1.1) (2016-05-09)
+
+
+### :star: New Features
+
+* auto installation for standalone ([2b0dc09](https://github.com/kazupon/vue-i18n/commit/2b0dc09))
+
+
+
+<a name="3.1.0"></a>
+# [3.1.0](https://github.com/kazupon/vue-i18n/compare/v3.0.0...v3.1.0) (2016-05-09)
+
+
+### :star: New Features
+
+* component locales ([12fe695](https://github.com/kazupon/vue-i18n/commit/12fe695)), closes [#29](https://github.com/kazupon/vue-i18n/issues/29)
+
+
+### :warning: Depcreted
+
+* **options:** remove Vue.use options ([d87b59b](https://github.com/kazupon/vue-i18n/commit/d87b59b))
+
+
+### :zap: Improvements
+
+* **keypath:** port the object path parser ([3ae04b7](https://github.com/kazupon/vue-i18n/commit/3ae04b7))
+* **translation:** fix hypenate included key translating ([d0a415f](https://github.com/kazupon/vue-i18n/commit/d0a415f)), closes [#24](https://github.com/kazupon/vue-i18n/issues/24)
+* **translation:** warning outputing when cannot translate with keypath ([b4c7c0e](https://github.com/kazupon/vue-i18n/commit/b4c7c0e)), closes [#22](https://github.com/kazupon/vue-i18n/issues/22)
+
+
+
+<a name="3.0.0"></a>
+# [3.0.0](https://github.com/kazupon/vue-i18n/compare/v2.4.1...v3.0.0) (2016-04-18)
+
+
+### Features
+
+* **lang:** support lang reactive changing ([203ee85](https://github.com/kazupon/vue-i18n/commit/203ee85)), closes [#2](https://github.com/kazupon/vue-i18n/issues/2) [#15](https://github.com/kazupon/vue-i18n/issues/15)
+* **locale:** support dynamic local ([4d61e8d](https://github.com/kazupon/vue-i18n/commit/4d61e8d)), closes [#6](https://github.com/kazupon/vue-i18n/issues/6) [#21](https://github.com/kazupon/vue-i18n/issues/21)
+
+### DEPRECATED
+
+* **index:** plugin install `Vue.use` options (`options.locales`, `options.lang`). See [README](https://github.com/kazupon/vue-i18n/blob/dev/README.md)
+
+
+<a name="2.4.1"></a>
+## [2.4.1](https://github.com/kazupon/vue-i18n/compare/v2.4.0...v2.4.1) (2016-02-29)
+
+### Features
+
+* **i18n:** support ruby on rails i18n interpolation format ([b6b2490](https://github.com/kazupon/vue-i18n/commit/b6b2490))
+
+
+
+<a name="2.4.0"></a>
+# [2.4.0](https://github.com/kazupon/vue-i18n/compare/v2.3.3...v2.4.0) (2016-02-06)
+
+
+### Features
+
+* **i18n:** add Vue.t function ([68935e3](https://github.com/kazupon/vue-i18n/commit/68935e3)), closes [#17](https://github.com/kazupon/vue-i18n/issues/17)
+
+
+
+<a name="2.3.3"></a>
+## [2.3.3](https://github.com/kazupon/vue-i18n/compare/v2.3.2...v2.3.3) (2015-12-09)
+
+
+### Bug Fixes
+
+* **npm:** npm install error ([e31e89e](https://github.com/kazupon/vue-i18n/commit/e31e89e))
+
+### Features
+
+* **bower:** good-bye bower :wink: ([d99eb15](https://github.com/kazupon/vue-i18n/commit/d99eb15))
+
+
+### BREAKING CHANGES
+
+* bower: not support `bower` package manager
+
+I think that bower is dead. :no_good:
+
+
+
+<a name="2.3.2"></a>
+## [2.3.2](https://github.com/kazupon/vue-i18n/compare/v2.3.1...v2.3.2) (2015-12-09)
+
+
+### Features
+
+* **bundle:** more compact the vue-i18n distribution file ([2f32ecc](https://github.com/kazupon/vue-i18n/commit/2f32ecc))
+
+
+
+<a name="2.3.1"></a>
+## [2.3.1](https://github.com/kazupon/vue-i18n/compare/v2.3.0...v2.3.1) (2015-12-01)
+
+### Reverts
+
+* **index:** automatically install for standalone ([25b8059](https://github.com/kazupon/vue-i18n/commit/25b8059))
+
+
+
+<a name="2.3.0"></a>
+# [2.3.0](https://github.com/kazupon/vue-i18n/compare/v2.2.0...v2.3.0) (2015-11-26)
+
+
+### Bug Fixes
+
+* **index:** cannot work at Vue 1.0.10 later ([6fd543e](https://github.com/kazupon/vue-i18n/commit/6fd543e)), closes [#9](https://github.com/kazupon/vue-i18n/issues/9)
+
+### Features
+
+* **index:** support automatically install for standalone ([ada2673](https://github.com/kazupon/vue-i18n/commit/ada2673))
+
+
+
+# v2.2.0 / 2015-09-16
+
+* Re-implemetation with ES6 (babel)
+
+# v2.1.0 / 2015-07-03
+
+* Add global local language setting with `Vue.config.lang`
+
+# v2.0.0 / 2015-06-29
+
+* Support Vue.js 0.12
+* Remove the followings (Breaking Changes)
+    * `Vue.t` function
+    * `v-t` directive
+
+# v1.1.1 / 2015-04-21
+
+* Fix unit test error
+
+# v1.1.0 / 2015-01-10
+
+* Support template string in `$t` method
+* Support language changing in `$t` method
+
+# v1.0.0 / 2015-01-10
+
+* Add `$t` method
+
+# v0.11.0 / 2014-11-07
+
+* Bump to 0.11.0
+
+# v0.2.0 / 2014-10-08
+
+* Support Vue.js 0.11.0-rc
+
+# v0.1.2 / 2014-10-07
+
+* Support bower
+
+# v0.1.1 / 2014-10-06
+
+* Add `Vue.t` function
+
+# v0.1.0 / 2014-05-06
+
+* Release first
+
+# v0.0.0 / 2014-05-03
+
+* Initial project

+ 20 - 0
plugin/vue-i18n/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 kazuya kawaguchi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 73 - 0
plugin/vue-i18n/README.md

@@ -0,0 +1,73 @@
+<p align="center"><img width="128px" height="112px" src="./assets/vue-i18n-logo.png" alt="Vue I18n logo"></p>
+<h1 align="center">vue-i18n</h1>
+<p align="center">
+  <a href="https://circleci.com/gh/kazupon/vue-i18n/tree/dev"><img src="https://circleci.com/gh/kazupon/vue-i18n/tree/dev.svg?style=shield" alt="Build Status"></a>
+  <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>
+  <a href="http://badge.fury.io/js/vue-i18n"><img src="https://badge.fury.io/js/vue-i18n.svg" alt="NPM version"></a>
+  <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>
+  <a href="https://devtoken.rocks/package/vue-i18n"><img src="https://badge.devtoken.rocks/vue-i18n" alt="vue-i18n Dev Token"></a>
+</p>
+
+<p align="center">Internationalization plugin for Vue.js</p>
+
+<br/>
+
+<h3 align="center">Silver Sponsors</h3>
+
+<p align="center">
+  <a href="https://www.codeandweb.com/babeledit?utm_campaign=vue-i18n-2019-01" target="_blank">
+    <img src="https://raw.githubusercontent.com/kazupon/vue-i18n/dev/vuepress/.vuepress/public/patrons/babeledit.png">
+  </a>
+</p>
+
+<h3 align="center">Bronze Sponsors</h3>
+
+<p align="center">
+  <a href="https://zenarchitects.co.jp/" target="_blank">
+    <img src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/zenarchitects.png">
+  </a>
+</p>
+
+<br/>
+
+<p align="center">
+  <a href="https://www.patreon.com/kazupon" target="_blank">
+    <img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patreon">
+  </a>
+</p>
+
+<br/>
+
+## :loudspeaker: Notice
+
+vue-i18n will soon be transferred to [intlify organization](https://github.com/intlify). After that, it will be developed and maintained on intlify.
+
+The `vue-i18n` that has been released on npm will be released as `@intlify/vue-i18n` in near future.
+
+`@intlify/vue-i18n` repo is [here](https://github.com/intlify/vue-i18n-next)
+
+Intlify is a new i18n project kickoff by @kazupon. 😉
+
+## :book: Documentation
+
+See [here](http://kazupon.github.io/vue-i18n/)
+
+
+## :scroll: Changelog
+
+Detailed changes for each release are documented in the [CHANGELOG.md](https://github.com/kazupon/vue-i18n/blob/dev/CHANGELOG.md).
+
+
+## :exclamation: Issues
+
+Please make sure to read the [Issue Reporting Checklist](https://github.com/kazupon/vue-i18n/blob/dev/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
+
+
+## :muscle: Contribution
+
+Please make sure to read the [Contributing Guide](https://github.com/kazupon/vue-i18n/blob/dev/CONTRIBUTING.md) before making a pull request.
+
+
+## :copyright: License
+
+[MIT](http://opensource.org/licenses/MIT)

+ 160 - 0
plugin/vue-i18n/decls/i18n.js

@@ -0,0 +1,160 @@
+declare var Intl: any;
+
+declare type Path = string;
+declare type Locale = string;
+declare type MessageContext = {
+  list: (index: number) => mixed,
+  named: (key: string) => mixed
+}
+declare type MessageFunction = (ctx: MessageContext) => string
+declare type FallbackLocale = string | string[] | false | { [locale: string]: string[] };
+declare type LocaleMessage = string | MessageFunction | LocaleMessageObject | LocaleMessageArray;
+declare type LocaleMessageObject = { [key: Path]: LocaleMessage };
+declare type LocaleMessageArray = Array<LocaleMessage>;
+declare type LocaleMessages = { [key: Locale]: LocaleMessageObject };
+
+// This options is the same as Intl.DateTimeFormat constructor options:
+// http://www.ecma-international.org/ecma-402/2.0/#sec-intl-datetimeformat-constructor
+declare type DateTimeFormatOptions = {
+  year?: 'numeric' | '2-digit',
+  month?: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long',
+  day?: 'numeric' | '2-digit',
+  hour?: 'numeric' | '2-digit',
+  minute?: 'numeric' | '2-digit',
+  second?: 'numeric' | '2-digit',
+  weekday?: 'narrow' | 'short' | 'long',
+  hour12?: boolean,
+  era?: 'narrow' | 'short' | 'long',
+  timeZone?: string, // IANA time zone
+  timeZoneName?: 'short' | 'long',
+  localeMatcher?: 'lookup' | 'best fit',
+  formatMatcher?: 'basic' | 'best fit'
+};
+declare type DateTimeFormat = { [key: string]: DateTimeFormatOptions };
+declare type DateTimeFormats = { [key: Locale]: DateTimeFormat };
+
+// This options is the same as Intl.NumberFormat constructor options:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
+declare type NumberFormatOptions = {
+  style?: 'decimal' | 'currency' | 'percent',
+  currency?: string, // ISO 4217 currency codes
+  currencyDisplay?: 'symbol' | 'code' | 'name',
+  useGrouping?: boolean,
+  minimumIntegerDigits?: number,
+  minimumFractionDigits?: number,
+  maximumFractionDigits?: number,
+  minimumSignificantDigits?: number,
+  maximumSignificantDigits?: number,
+  localeMatcher?: 'lookup' | 'best fit',
+  formatMatcher?: 'basic' | 'best fit'
+};
+declare type NumberFormat = { [key: string]: NumberFormatOptions };
+declare type NumberFormats = { [key: Locale]: NumberFormat };
+declare type Modifiers = { [key: string]: (str: string) => string };
+
+declare type TranslateResult = string | LocaleMessages;
+declare type DateTimeFormatResult = string;
+declare type NumberFormatResult = string;
+declare type MissingHandler = (locale: Locale, key: Path, vm?: any) => string | void;
+declare type PostTranslationHandler = (str: string, key?: string) => string;
+declare type GetChoiceIndex = (choice: number, choicesLength: number) => number
+declare type ComponentInstanceCreatedListener = (newI18n: I18n, rootI18n: I18n) => void;
+
+declare type FormattedNumberPartType = 'currency' | 'decimal' | 'fraction' | 'group' | 'infinity' | 'integer' | 'literal' | 'minusSign' | 'nan' | 'plusSign' | 'percentSign';
+declare type FormattedNumberPart = {
+  type: FormattedNumberPartType,
+  value: string,
+};
+// This array is the same as Intl.NumberFormat.formatToParts() return value:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat/formatToParts#Return_value
+declare type NumberFormatToPartsResult = Array<FormattedNumberPart>;
+
+declare type WarnHtmlInMessageLevel = 'off' | 'warn' | 'error';
+
+declare type I18nOptions = {
+  locale?: Locale,
+  fallbackLocale?: FallbackLocale,
+  messages?: LocaleMessages,
+  dateTimeFormats?: DateTimeFormats,
+  numberFormats?: NumberFormats,
+  formatter?: Formatter,
+  missing?: MissingHandler,
+  modifiers?: Modifiers,
+  root?: I18n, // for internal
+  fallbackRoot?: boolean,
+  formatFallbackMessages?: boolean,
+  sync?: boolean,
+  silentTranslationWarn?: boolean | RegExp,
+  silentFallbackWarn?: boolean | RegExp,
+  pluralizationRules?: PluralizationRules,
+  preserveDirectiveContent?: boolean,
+  warnHtmlInMessage?: WarnHtmlInMessageLevel,
+  sharedMessages?: LocaleMessage,
+  postTranslation?: PostTranslationHandler,
+  componentInstanceCreatedListener?: ComponentInstanceCreatedListener,
+};
+
+declare type IntlAvailability = {
+  dateTimeFormat: boolean,
+  numberFormat: boolean
+};
+
+declare type PluralizationRules = {
+  [lang: string]: GetChoiceIndex,
+}
+
+declare interface I18n {
+  static install: () => void, // for Vue plugin interface
+  static version: string,
+  static availabilities: IntlAvailability,
+  get vm (): any, // for internal
+  get locale (): Locale,
+  set locale (locale: Locale): void,
+  get fallbackLocale (): FallbackLocale,
+  set fallbackLocale (locale: FallbackLocale): void,
+  get messages (): LocaleMessages,
+  get dateTimeFormats (): DateTimeFormats,
+  get numberFormats (): NumberFormats,
+  get availableLocales (): Locale[],
+  get missing (): ?MissingHandler,
+  set missing (handler: MissingHandler): void,
+  get formatter (): Formatter,
+  set formatter (formatter: Formatter): void,
+  get formatFallbackMessages (): boolean,
+  set formatFallbackMessages (fallback: boolean): void,
+  get silentTranslationWarn (): boolean | RegExp,
+  set silentTranslationWarn (silent: boolean | RegExp): void,
+  get silentFallbackWarn (): boolean | RegExp,
+  set silentFallbackWarn (slient: boolean | RegExp): void,
+  get pluralizationRules (): PluralizationRules,
+  set pluralizationRules (rules: PluralizationRules): void,
+  get preserveDirectiveContent (): boolean,
+  set preserveDirectiveContent (preserve: boolean): void,
+  get warnHtmlInMessage (): WarnHtmlInMessageLevel,
+  set warnHtmlInMessage (level: WarnHtmlInMessageLevel): void,
+  get postTranslation (): ?PostTranslationHandler,
+  set postTranslation (handler: PostTranslationHandler): void,
+
+  getLocaleMessage (locale: Locale): LocaleMessageObject,
+  setLocaleMessage (locale: Locale, message: LocaleMessageObject): void,
+  mergeLocaleMessage (locale: Locale, message: LocaleMessageObject): void,
+  t (key: Path, ...values: any): TranslateResult,
+  i (key: Path, locale: Locale, values: Object): TranslateResult,
+  tc (key: Path, choice?: number, ...values: any): TranslateResult,
+  te (key: Path, locale?: Locale): boolean,
+  getDateTimeFormat (locale: Locale): DateTimeFormat,
+  setDateTimeFormat (locale: Locale, format: DateTimeFormat): void,
+  mergeDateTimeFormat (locale: Locale, format: DateTimeFormat): void,
+  d (value: number | Date, ...args: any): DateTimeFormatResult,
+  getNumberFormat (locale: Locale): NumberFormat,
+  setNumberFormat (locale: Locale, format: NumberFormat): void,
+  mergeNumberFormat (locale: Locale, format: NumberFormat): void,
+  n (value: number, ...args: any): NumberFormatResult,
+  getChoiceIndex: GetChoiceIndex,
+  pluralizationRules: PluralizationRules,
+  preserveDirectiveContent: boolean
+};
+
+declare interface Formatter {
+  interpolate (message: string, values: any, path: string): (Array<any> | null)
+};

+ 30 - 0
plugin/vue-i18n/decls/module.js

@@ -0,0 +1,30 @@
+declare type $npm$Vue$Dictionaly<T> = { [key: string]: T }
+
+declare type Util = {
+  extend: (to: Object, from: ?Object) => Object,
+  hasOwn: (obj: Object, key: string) => boolean,
+  isPlainObject: (obj: any) => boolean,
+  isObject: (obj: mixed) => boolean,
+}
+
+declare type Config = {
+  optionMergeStrategies: $npm$Vue$Dictionaly<Function>,
+  silent: boolean,
+  productionTip: boolean,
+  performance: boolean,
+  devtools: boolean,
+  errorHandler: ?(err: Error, vm: Vue, info: string) => void,
+  ignoredElements: Array<string>,
+  keyCodes: $npm$Vue$Dictionaly<number>,
+  isReservedTag: (x?: string) => boolean,
+  parsePlatformTagName: (x: string) => string,
+  isUnknownElement: (x?: string) => boolean,
+  getTagNamespace: (x?: string) => string | void,
+  mustUseProp: (tag: string, type: ?string, name: string) => boolean,
+}
+
+declare interface Vue {
+  static config: Config,
+  static util: Util,
+  static version: string,
+}

+ 2151 - 0
plugin/vue-i18n/dist/vue-i18n.common.js

@@ -0,0 +1,2151 @@
+/*!
+ * vue-i18n v8.21.0 
+ * (c) 2020 kazuya kawaguchi
+ * Released under the MIT License.
+ */
+'use strict';
+
+/*  */
+
+/**
+ * constants
+ */
+
+var numberFormatKeys = [
+  'style',
+  'currency',
+  'currencyDisplay',
+  'useGrouping',
+  'minimumIntegerDigits',
+  'minimumFractionDigits',
+  'maximumFractionDigits',
+  'minimumSignificantDigits',
+  'maximumSignificantDigits',
+  'localeMatcher',
+  'formatMatcher',
+  'unit'
+];
+
+/**
+ * utilities
+ */
+
+function warn (msg, err) {
+  if (typeof console !== 'undefined') {
+    console.warn('[vue-i18n] ' + msg);
+    /* istanbul ignore if */
+    if (err) {
+      console.warn(err.stack);
+    }
+  }
+}
+
+function error (msg, err) {
+  if (typeof console !== 'undefined') {
+    console.error('[vue-i18n] ' + msg);
+    /* istanbul ignore if */
+    if (err) {
+      console.error(err.stack);
+    }
+  }
+}
+
+var isArray = Array.isArray;
+
+function isObject (obj) {
+  return obj !== null && typeof obj === 'object'
+}
+
+function isBoolean (val) {
+  return typeof val === 'boolean'
+}
+
+function isString (val) {
+  return typeof val === 'string'
+}
+
+var toString = Object.prototype.toString;
+var OBJECT_STRING = '[object Object]';
+function isPlainObject (obj) {
+  return toString.call(obj) === OBJECT_STRING
+}
+
+function isNull (val) {
+  return val === null || val === undefined
+}
+
+function isFunction (val) {
+  return typeof val === 'function'
+}
+
+function parseArgs () {
+  var args = [], len = arguments.length;
+  while ( len-- ) args[ len ] = arguments[ len ];
+
+  var locale = null;
+  var params = null;
+  if (args.length === 1) {
+    if (isObject(args[0]) || isArray(args[0])) {
+      params = args[0];
+    } else if (typeof args[0] === 'string') {
+      locale = args[0];
+    }
+  } else if (args.length === 2) {
+    if (typeof args[0] === 'string') {
+      locale = args[0];
+    }
+    /* istanbul ignore if */
+    if (isObject(args[1]) || isArray(args[1])) {
+      params = args[1];
+    }
+  }
+
+  return { locale: locale, params: params }
+}
+
+function looseClone (obj) {
+  return JSON.parse(JSON.stringify(obj))
+}
+
+function remove (arr, item) {
+  if (arr.length) {
+    var index = arr.indexOf(item);
+    if (index > -1) {
+      return arr.splice(index, 1)
+    }
+  }
+}
+
+function includes (arr, item) {
+  return !!~arr.indexOf(item)
+}
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+function hasOwn (obj, key) {
+  return hasOwnProperty.call(obj, key)
+}
+
+function merge (target) {
+  var arguments$1 = arguments;
+
+  var output = Object(target);
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments$1[i];
+    if (source !== undefined && source !== null) {
+      var key = (void 0);
+      for (key in source) {
+        if (hasOwn(source, key)) {
+          if (isObject(source[key])) {
+            output[key] = merge(output[key], source[key]);
+          } else {
+            output[key] = source[key];
+          }
+        }
+      }
+    }
+  }
+  return output
+}
+
+function looseEqual (a, b) {
+  if (a === b) { return true }
+  var isObjectA = isObject(a);
+  var isObjectB = isObject(b);
+  if (isObjectA && isObjectB) {
+    try {
+      var isArrayA = isArray(a);
+      var isArrayB = isArray(b);
+      if (isArrayA && isArrayB) {
+        return a.length === b.length && a.every(function (e, i) {
+          return looseEqual(e, b[i])
+        })
+      } else if (!isArrayA && !isArrayB) {
+        var keysA = Object.keys(a);
+        var keysB = Object.keys(b);
+        return keysA.length === keysB.length && keysA.every(function (key) {
+          return looseEqual(a[key], b[key])
+        })
+      } else {
+        /* istanbul ignore next */
+        return false
+      }
+    } catch (e) {
+      /* istanbul ignore next */
+      return false
+    }
+  } else if (!isObjectA && !isObjectB) {
+    return String(a) === String(b)
+  } else {
+    return false
+  }
+}
+
+/*  */
+
+function extend (Vue) {
+  if (!Vue.prototype.hasOwnProperty('$i18n')) {
+    // $FlowFixMe
+    Object.defineProperty(Vue.prototype, '$i18n', {
+      get: function get () { return this._i18n }
+    });
+  }
+
+  Vue.prototype.$t = function (key) {
+    var values = [], len = arguments.length - 1;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 1 ];
+
+    var i18n = this.$i18n;
+    return i18n._t.apply(i18n, [ key, i18n.locale, i18n._getMessages(), this ].concat( values ))
+  };
+
+  Vue.prototype.$tc = function (key, choice) {
+    var values = [], len = arguments.length - 2;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 2 ];
+
+    var i18n = this.$i18n;
+    return i18n._tc.apply(i18n, [ key, i18n.locale, i18n._getMessages(), this, choice ].concat( values ))
+  };
+
+  Vue.prototype.$te = function (key, locale) {
+    var i18n = this.$i18n;
+    return i18n._te(key, i18n.locale, i18n._getMessages(), locale)
+  };
+
+  Vue.prototype.$d = function (value) {
+    var ref;
+
+    var args = [], len = arguments.length - 1;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+    return (ref = this.$i18n).d.apply(ref, [ value ].concat( args ))
+  };
+
+  Vue.prototype.$n = function (value) {
+    var ref;
+
+    var args = [], len = arguments.length - 1;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+    return (ref = this.$i18n).n.apply(ref, [ value ].concat( args ))
+  };
+}
+
+/*  */
+
+var mixin = {
+  beforeCreate: function beforeCreate () {
+    var options = this.$options;
+    options.i18n = options.i18n || (options.__i18n ? {} : null);
+
+    if (options.i18n) {
+      if (options.i18n instanceof VueI18n) {
+        // init locale messages via custom blocks
+        if (options.__i18n) {
+          try {
+            var localeMessages = {};
+            options.__i18n.forEach(function (resource) {
+              localeMessages = merge(localeMessages, JSON.parse(resource));
+            });
+            Object.keys(localeMessages).forEach(function (locale) {
+              options.i18n.mergeLocaleMessage(locale, localeMessages[locale]);
+            });
+          } catch (e) {
+            if (process.env.NODE_ENV !== 'production') {
+              error("Cannot parse locale messages via custom blocks.", e);
+            }
+          }
+        }
+        this._i18n = options.i18n;
+        this._i18nWatcher = this._i18n.watchI18nData();
+      } else if (isPlainObject(options.i18n)) {
+        var rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
+          ? this.$root.$i18n
+          : null;
+        // component local i18n
+        if (rootI18n) {
+          options.i18n.root = this.$root;
+          options.i18n.formatter = rootI18n.formatter;
+          options.i18n.fallbackLocale = rootI18n.fallbackLocale;
+          options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages;
+          options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn;
+          options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn;
+          options.i18n.pluralizationRules = rootI18n.pluralizationRules;
+          options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent;
+        }
+
+        // init locale messages via custom blocks
+        if (options.__i18n) {
+          try {
+            var localeMessages$1 = {};
+            options.__i18n.forEach(function (resource) {
+              localeMessages$1 = merge(localeMessages$1, JSON.parse(resource));
+            });
+            options.i18n.messages = localeMessages$1;
+          } catch (e) {
+            if (process.env.NODE_ENV !== 'production') {
+              warn("Cannot parse locale messages via custom blocks.", e);
+            }
+          }
+        }
+
+        var ref = options.i18n;
+        var sharedMessages = ref.sharedMessages;
+        if (sharedMessages && isPlainObject(sharedMessages)) {
+          options.i18n.messages = merge(options.i18n.messages, sharedMessages);
+        }
+
+        this._i18n = new VueI18n(options.i18n);
+        this._i18nWatcher = this._i18n.watchI18nData();
+
+        if (options.i18n.sync === undefined || !!options.i18n.sync) {
+          this._localeWatcher = this.$i18n.watchLocale();
+        }
+
+        if (rootI18n) {
+          rootI18n.onComponentInstanceCreated(this._i18n);
+        }
+      } else {
+        if (process.env.NODE_ENV !== 'production') {
+          warn("Cannot be interpreted 'i18n' option.");
+        }
+      }
+    } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+      // root i18n
+      this._i18n = this.$root.$i18n;
+    } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+      // parent i18n
+      this._i18n = options.parent.$i18n;
+    }
+  },
+
+  beforeMount: function beforeMount () {
+    var options = this.$options;
+    options.i18n = options.i18n || (options.__i18n ? {} : null);
+
+    if (options.i18n) {
+      if (options.i18n instanceof VueI18n) {
+        // init locale messages via custom blocks
+        this._i18n.subscribeDataChanging(this);
+        this._subscribing = true;
+      } else if (isPlainObject(options.i18n)) {
+        this._i18n.subscribeDataChanging(this);
+        this._subscribing = true;
+      } else {
+        if (process.env.NODE_ENV !== 'production') {
+          warn("Cannot be interpreted 'i18n' option.");
+        }
+      }
+    } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+      this._i18n.subscribeDataChanging(this);
+      this._subscribing = true;
+    } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+      this._i18n.subscribeDataChanging(this);
+      this._subscribing = true;
+    }
+  },
+
+  beforeDestroy: function beforeDestroy () {
+    if (!this._i18n) { return }
+
+    var self = this;
+    this.$nextTick(function () {
+      if (self._subscribing) {
+        self._i18n.unsubscribeDataChanging(self);
+        delete self._subscribing;
+      }
+
+      if (self._i18nWatcher) {
+        self._i18nWatcher();
+        self._i18n.destroyVM();
+        delete self._i18nWatcher;
+      }
+
+      if (self._localeWatcher) {
+        self._localeWatcher();
+        delete self._localeWatcher;
+      }
+    });
+  }
+};
+
+/*  */
+
+var interpolationComponent = {
+  name: 'i18n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    path: {
+      type: String,
+      required: true
+    },
+    locale: {
+      type: String
+    },
+    places: {
+      type: [Array, Object]
+    }
+  },
+  render: function render (h, ref) {
+    var data = ref.data;
+    var parent = ref.parent;
+    var props = ref.props;
+    var slots = ref.slots;
+
+    var $i18n = parent.$i18n;
+    if (!$i18n) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot find VueI18n instance!');
+      }
+      return
+    }
+
+    var path = props.path;
+    var locale = props.locale;
+    var places = props.places;
+    var params = slots();
+    var children = $i18n.i(
+      path,
+      locale,
+      onlyHasDefaultPlace(params) || places
+        ? useLegacyPlaces(params.default, places)
+        : params
+    );
+
+    var tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span';
+    return tag ? h(tag, data, children) : children
+  }
+};
+
+function onlyHasDefaultPlace (params) {
+  var prop;
+  for (prop in params) {
+    if (prop !== 'default') { return false }
+  }
+  return Boolean(prop)
+}
+
+function useLegacyPlaces (children, places) {
+  var params = places ? createParamsFromPlaces(places) : {};
+
+  if (!children) { return params }
+
+  // Filter empty text nodes
+  children = children.filter(function (child) {
+    return child.tag || child.text.trim() !== ''
+  });
+
+  var everyPlace = children.every(vnodeHasPlaceAttribute);
+  if (process.env.NODE_ENV !== 'production' && everyPlace) {
+    warn('`place` attribute is deprecated in next major version. Please switch to Vue slots.');
+  }
+
+  return children.reduce(
+    everyPlace ? assignChildPlace : assignChildIndex,
+    params
+  )
+}
+
+function createParamsFromPlaces (places) {
+  if (process.env.NODE_ENV !== 'production') {
+    warn('`places` prop is deprecated in next major version. Please switch to Vue slots.');
+  }
+
+  return Array.isArray(places)
+    ? places.reduce(assignChildIndex, {})
+    : Object.assign({}, places)
+}
+
+function assignChildPlace (params, child) {
+  if (child.data && child.data.attrs && child.data.attrs.place) {
+    params[child.data.attrs.place] = child;
+  }
+  return params
+}
+
+function assignChildIndex (params, child, index) {
+  params[index] = child;
+  return params
+}
+
+function vnodeHasPlaceAttribute (vnode) {
+  return Boolean(vnode.data && vnode.data.attrs && vnode.data.attrs.place)
+}
+
+/*  */
+
+var numberComponent = {
+  name: 'i18n-n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    value: {
+      type: Number,
+      required: true
+    },
+    format: {
+      type: [String, Object]
+    },
+    locale: {
+      type: String
+    }
+  },
+  render: function render (h, ref) {
+    var props = ref.props;
+    var parent = ref.parent;
+    var data = ref.data;
+
+    var i18n = parent.$i18n;
+
+    if (!i18n) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot find VueI18n instance!');
+      }
+      return null
+    }
+
+    var key = null;
+    var options = null;
+
+    if (isString(props.format)) {
+      key = props.format;
+    } else if (isObject(props.format)) {
+      if (props.format.key) {
+        key = props.format.key;
+      }
+
+      // Filter out number format options only
+      options = Object.keys(props.format).reduce(function (acc, prop) {
+        var obj;
+
+        if (includes(numberFormatKeys, prop)) {
+          return Object.assign({}, acc, ( obj = {}, obj[prop] = props.format[prop], obj ))
+        }
+        return acc
+      }, null);
+    }
+
+    var locale = props.locale || i18n.locale;
+    var parts = i18n._ntp(props.value, locale, key, options);
+
+    var values = parts.map(function (part, index) {
+      var obj;
+
+      var slot = data.scopedSlots && data.scopedSlots[part.type];
+      return slot ? slot(( obj = {}, obj[part.type] = part.value, obj.index = index, obj.parts = parts, obj )) : part.value
+    });
+
+    var tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span';
+    return tag
+      ? h(tag, {
+        attrs: data.attrs,
+        'class': data['class'],
+        staticClass: data.staticClass
+      }, values)
+      : values
+  }
+};
+
+/*  */
+
+function bind (el, binding, vnode) {
+  if (!assert(el, vnode)) { return }
+
+  t(el, binding, vnode);
+}
+
+function update (el, binding, vnode, oldVNode) {
+  if (!assert(el, vnode)) { return }
+
+  var i18n = vnode.context.$i18n;
+  if (localeEqual(el, vnode) &&
+    (looseEqual(binding.value, binding.oldValue) &&
+     looseEqual(el._localeMessage, i18n.getLocaleMessage(i18n.locale)))) { return }
+
+  t(el, binding, vnode);
+}
+
+function unbind (el, binding, vnode, oldVNode) {
+  var vm = vnode.context;
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context');
+    return
+  }
+
+  var i18n = vnode.context.$i18n || {};
+  if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
+    el.textContent = '';
+  }
+  el._vt = undefined;
+  delete el['_vt'];
+  el._locale = undefined;
+  delete el['_locale'];
+  el._localeMessage = undefined;
+  delete el['_localeMessage'];
+}
+
+function assert (el, vnode) {
+  var vm = vnode.context;
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context');
+    return false
+  }
+
+  if (!vm.$i18n) {
+    warn('VueI18n instance does not exists in Vue instance');
+    return false
+  }
+
+  return true
+}
+
+function localeEqual (el, vnode) {
+  var vm = vnode.context;
+  return el._locale === vm.$i18n.locale
+}
+
+function t (el, binding, vnode) {
+  var ref$1, ref$2;
+
+  var value = binding.value;
+
+  var ref = parseValue(value);
+  var path = ref.path;
+  var locale = ref.locale;
+  var args = ref.args;
+  var choice = ref.choice;
+  if (!path && !locale && !args) {
+    warn('value type not supported');
+    return
+  }
+
+  if (!path) {
+    warn('`path` is required in v-t directive');
+    return
+  }
+
+  var vm = vnode.context;
+  if (choice != null) {
+    el._vt = el.textContent = (ref$1 = vm.$i18n).tc.apply(ref$1, [ path, choice ].concat( makeParams(locale, args) ));
+  } else {
+    el._vt = el.textContent = (ref$2 = vm.$i18n).t.apply(ref$2, [ path ].concat( makeParams(locale, args) ));
+  }
+  el._locale = vm.$i18n.locale;
+  el._localeMessage = vm.$i18n.getLocaleMessage(vm.$i18n.locale);
+}
+
+function parseValue (value) {
+  var path;
+  var locale;
+  var args;
+  var choice;
+
+  if (isString(value)) {
+    path = value;
+  } else if (isPlainObject(value)) {
+    path = value.path;
+    locale = value.locale;
+    args = value.args;
+    choice = value.choice;
+  }
+
+  return { path: path, locale: locale, args: args, choice: choice }
+}
+
+function makeParams (locale, args) {
+  var params = [];
+
+  locale && params.push(locale);
+  if (args && (Array.isArray(args) || isPlainObject(args))) {
+    params.push(args);
+  }
+
+  return params
+}
+
+var Vue;
+
+function install (_Vue) {
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && install.installed && _Vue === Vue) {
+    warn('already installed.');
+    return
+  }
+  install.installed = true;
+
+  Vue = _Vue;
+
+  var version = (Vue.version && Number(Vue.version.split('.')[0])) || -1;
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && version < 2) {
+    warn(("vue-i18n (" + (install.version) + ") need to use Vue 2.0 or later (Vue: " + (Vue.version) + ")."));
+    return
+  }
+
+  extend(Vue);
+  Vue.mixin(mixin);
+  Vue.directive('t', { bind: bind, update: update, unbind: unbind });
+  Vue.component(interpolationComponent.name, interpolationComponent);
+  Vue.component(numberComponent.name, numberComponent);
+
+  // use simple mergeStrategies to prevent i18n instance lose '__proto__'
+  var strats = Vue.config.optionMergeStrategies;
+  strats.i18n = function (parentVal, childVal) {
+    return childVal === undefined
+      ? parentVal
+      : childVal
+  };
+}
+
+/*  */
+
+var BaseFormatter = function BaseFormatter () {
+  this._caches = Object.create(null);
+};
+
+BaseFormatter.prototype.interpolate = function interpolate (message, values) {
+  if (!values) {
+    return [message]
+  }
+  var tokens = this._caches[message];
+  if (!tokens) {
+    tokens = parse(message);
+    this._caches[message] = tokens;
+  }
+  return compile(tokens, values)
+};
+
+
+
+var RE_TOKEN_LIST_VALUE = /^(?:\d)+/;
+var RE_TOKEN_NAMED_VALUE = /^(?:\w)+/;
+
+function parse (format) {
+  var tokens = [];
+  var position = 0;
+
+  var text = '';
+  while (position < format.length) {
+    var char = format[position++];
+    if (char === '{') {
+      if (text) {
+        tokens.push({ type: 'text', value: text });
+      }
+
+      text = '';
+      var sub = '';
+      char = format[position++];
+      while (char !== undefined && char !== '}') {
+        sub += char;
+        char = format[position++];
+      }
+      var isClosed = char === '}';
+
+      var type = RE_TOKEN_LIST_VALUE.test(sub)
+        ? 'list'
+        : isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
+          ? 'named'
+          : 'unknown';
+      tokens.push({ value: sub, type: type });
+    } else if (char === '%') {
+      // when found rails i18n syntax, skip text capture
+      if (format[(position)] !== '{') {
+        text += char;
+      }
+    } else {
+      text += char;
+    }
+  }
+
+  text && tokens.push({ type: 'text', value: text });
+
+  return tokens
+}
+
+function compile (tokens, values) {
+  var compiled = [];
+  var index = 0;
+
+  var mode = Array.isArray(values)
+    ? 'list'
+    : isObject(values)
+      ? 'named'
+      : 'unknown';
+  if (mode === 'unknown') { return compiled }
+
+  while (index < tokens.length) {
+    var token = tokens[index];
+    switch (token.type) {
+      case 'text':
+        compiled.push(token.value);
+        break
+      case 'list':
+        compiled.push(values[parseInt(token.value, 10)]);
+        break
+      case 'named':
+        if (mode === 'named') {
+          compiled.push((values)[token.value]);
+        } else {
+          if (process.env.NODE_ENV !== 'production') {
+            warn(("Type of token '" + (token.type) + "' and format of value '" + mode + "' don't match!"));
+          }
+        }
+        break
+      case 'unknown':
+        if (process.env.NODE_ENV !== 'production') {
+          warn("Detect 'unknown' type of token!");
+        }
+        break
+    }
+    index++;
+  }
+
+  return compiled
+}
+
+/*  */
+
+/**
+ *  Path parser
+ *  - Inspired:
+ *    Vue.js Path parser
+ */
+
+// actions
+var APPEND = 0;
+var PUSH = 1;
+var INC_SUB_PATH_DEPTH = 2;
+var PUSH_SUB_PATH = 3;
+
+// states
+var BEFORE_PATH = 0;
+var IN_PATH = 1;
+var BEFORE_IDENT = 2;
+var IN_IDENT = 3;
+var IN_SUB_PATH = 4;
+var IN_SINGLE_QUOTE = 5;
+var IN_DOUBLE_QUOTE = 6;
+var AFTER_PATH = 7;
+var ERROR = 8;
+
+var pathStateMachine = [];
+
+pathStateMachine[BEFORE_PATH] = {
+  'ws': [BEFORE_PATH],
+  'ident': [IN_IDENT, APPEND],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+};
+
+pathStateMachine[IN_PATH] = {
+  'ws': [IN_PATH],
+  '.': [BEFORE_IDENT],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+};
+
+pathStateMachine[BEFORE_IDENT] = {
+  'ws': [BEFORE_IDENT],
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND]
+};
+
+pathStateMachine[IN_IDENT] = {
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND],
+  'ws': [IN_PATH, PUSH],
+  '.': [BEFORE_IDENT, PUSH],
+  '[': [IN_SUB_PATH, PUSH],
+  'eof': [AFTER_PATH, PUSH]
+};
+
+pathStateMachine[IN_SUB_PATH] = {
+  "'": [IN_SINGLE_QUOTE, APPEND],
+  '"': [IN_DOUBLE_QUOTE, APPEND],
+  '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
+  ']': [IN_PATH, PUSH_SUB_PATH],
+  'eof': ERROR,
+  'else': [IN_SUB_PATH, APPEND]
+};
+
+pathStateMachine[IN_SINGLE_QUOTE] = {
+  "'": [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_SINGLE_QUOTE, APPEND]
+};
+
+pathStateMachine[IN_DOUBLE_QUOTE] = {
+  '"': [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_DOUBLE_QUOTE, APPEND]
+};
+
+/**
+ * Check if an expression is a literal value.
+ */
+
+var literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
+function isLiteral (exp) {
+  return literalValueRE.test(exp)
+}
+
+/**
+ * Strip quotes from a string
+ */
+
+function stripQuotes (str) {
+  var a = str.charCodeAt(0);
+  var b = str.charCodeAt(str.length - 1);
+  return a === b && (a === 0x22 || a === 0x27)
+    ? str.slice(1, -1)
+    : str
+}
+
+/**
+ * Determine the type of a character in a keypath.
+ */
+
+function getPathCharType (ch) {
+  if (ch === undefined || ch === null) { return 'eof' }
+
+  var code = ch.charCodeAt(0);
+
+  switch (code) {
+    case 0x5B: // [
+    case 0x5D: // ]
+    case 0x2E: // .
+    case 0x22: // "
+    case 0x27: // '
+      return ch
+
+    case 0x5F: // _
+    case 0x24: // $
+    case 0x2D: // -
+      return 'ident'
+
+    case 0x09: // Tab
+    case 0x0A: // Newline
+    case 0x0D: // Return
+    case 0xA0:  // No-break space
+    case 0xFEFF:  // Byte Order Mark
+    case 0x2028:  // Line Separator
+    case 0x2029:  // Paragraph Separator
+      return 'ws'
+  }
+
+  return 'ident'
+}
+
+/**
+ * Format a subPath, return its plain form if it is
+ * a literal string or number. Otherwise prepend the
+ * dynamic indicator (*).
+ */
+
+function formatSubPath (path) {
+  var trimmed = path.trim();
+  // invalid leading 0
+  if (path.charAt(0) === '0' && isNaN(path)) { return false }
+
+  return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed
+}
+
+/**
+ * Parse a string path into an array of segments
+ */
+
+function parse$1 (path) {
+  var keys = [];
+  var index = -1;
+  var mode = BEFORE_PATH;
+  var subPathDepth = 0;
+  var c;
+  var key;
+  var newChar;
+  var type;
+  var transition;
+  var action;
+  var typeMap;
+  var actions = [];
+
+  actions[PUSH] = function () {
+    if (key !== undefined) {
+      keys.push(key);
+      key = undefined;
+    }
+  };
+
+  actions[APPEND] = function () {
+    if (key === undefined) {
+      key = newChar;
+    } else {
+      key += newChar;
+    }
+  };
+
+  actions[INC_SUB_PATH_DEPTH] = function () {
+    actions[APPEND]();
+    subPathDepth++;
+  };
+
+  actions[PUSH_SUB_PATH] = function () {
+    if (subPathDepth > 0) {
+      subPathDepth--;
+      mode = IN_SUB_PATH;
+      actions[APPEND]();
+    } else {
+      subPathDepth = 0;
+      if (key === undefined) { return false }
+      key = formatSubPath(key);
+      if (key === false) {
+        return false
+      } else {
+        actions[PUSH]();
+      }
+    }
+  };
+
+  function maybeUnescapeQuote () {
+    var nextChar = path[index + 1];
+    if ((mode === IN_SINGLE_QUOTE && nextChar === "'") ||
+      (mode === IN_DOUBLE_QUOTE && nextChar === '"')) {
+      index++;
+      newChar = '\\' + nextChar;
+      actions[APPEND]();
+      return true
+    }
+  }
+
+  while (mode !== null) {
+    index++;
+    c = path[index];
+
+    if (c === '\\' && maybeUnescapeQuote()) {
+      continue
+    }
+
+    type = getPathCharType(c);
+    typeMap = pathStateMachine[mode];
+    transition = typeMap[type] || typeMap['else'] || ERROR;
+
+    if (transition === ERROR) {
+      return // parse error
+    }
+
+    mode = transition[0];
+    action = actions[transition[1]];
+    if (action) {
+      newChar = transition[2];
+      newChar = newChar === undefined
+        ? c
+        : newChar;
+      if (action() === false) {
+        return
+      }
+    }
+
+    if (mode === AFTER_PATH) {
+      return keys
+    }
+  }
+}
+
+
+
+
+
+var I18nPath = function I18nPath () {
+  this._cache = Object.create(null);
+};
+
+/**
+ * External parse that check for a cache hit first
+ */
+I18nPath.prototype.parsePath = function parsePath (path) {
+  var hit = this._cache[path];
+  if (!hit) {
+    hit = parse$1(path);
+    if (hit) {
+      this._cache[path] = hit;
+    }
+  }
+  return hit || []
+};
+
+/**
+ * Get path value from path string
+ */
+I18nPath.prototype.getPathValue = function getPathValue (obj, path) {
+  if (!isObject(obj)) { return null }
+
+  var paths = this.parsePath(path);
+  if (paths.length === 0) {
+    return null
+  } else {
+    var length = paths.length;
+    var last = obj;
+    var i = 0;
+    while (i < length) {
+      var value = last[paths[i]];
+      if (value === undefined) {
+        return null
+      }
+      last = value;
+      i++;
+    }
+
+    return last
+  }
+};
+
+/*  */
+
+
+
+var htmlTagMatcher = /<\/?[\w\s="/.':;#-\/]+>/;
+var linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
+var linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/;
+var bracketsMatcher = /[()]/g;
+var defaultModifiers = {
+  'upper': function (str) { return str.toLocaleUpperCase(); },
+  'lower': function (str) { return str.toLocaleLowerCase(); },
+  'capitalize': function (str) { return ("" + (str.charAt(0).toLocaleUpperCase()) + (str.substr(1))); }
+};
+
+var defaultFormatter = new BaseFormatter();
+
+var VueI18n = function VueI18n (options) {
+  var this$1 = this;
+  if ( options === void 0 ) options = {};
+
+  // Auto install if it is not done yet and `window` has `Vue`.
+  // To allow users to avoid auto-installation in some cases,
+  // this code should be placed here. See #290
+  /* istanbul ignore if */
+  if (!Vue && typeof window !== 'undefined' && window.Vue) {
+    install(window.Vue);
+  }
+
+  var locale = options.locale || 'en-US';
+  var fallbackLocale = options.fallbackLocale === false
+    ? false
+    : options.fallbackLocale || 'en-US';
+  var messages = options.messages || {};
+  var dateTimeFormats = options.dateTimeFormats || {};
+  var numberFormats = options.numberFormats || {};
+
+  this._vm = null;
+  this._formatter = options.formatter || defaultFormatter;
+  this._modifiers = options.modifiers || {};
+  this._missing = options.missing || null;
+  this._root = options.root || null;
+  this._sync = options.sync === undefined ? true : !!options.sync;
+  this._fallbackRoot = options.fallbackRoot === undefined
+    ? true
+    : !!options.fallbackRoot;
+  this._formatFallbackMessages = options.formatFallbackMessages === undefined
+    ? false
+    : !!options.formatFallbackMessages;
+  this._silentTranslationWarn = options.silentTranslationWarn === undefined
+    ? false
+    : options.silentTranslationWarn;
+  this._silentFallbackWarn = options.silentFallbackWarn === undefined
+    ? false
+    : !!options.silentFallbackWarn;
+  this._dateTimeFormatters = {};
+  this._numberFormatters = {};
+  this._path = new I18nPath();
+  this._dataListeners = [];
+  this._componentInstanceCreatedListener = options.componentInstanceCreatedListener || null;
+  this._preserveDirectiveContent = options.preserveDirectiveContent === undefined
+    ? false
+    : !!options.preserveDirectiveContent;
+  this.pluralizationRules = options.pluralizationRules || {};
+  this._warnHtmlInMessage = options.warnHtmlInMessage || 'off';
+  this._postTranslation = options.postTranslation || null;
+
+  /**
+   * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
+   * @param choicesLength {number} an overall amount of available choices
+   * @returns a final choice index
+  */
+  this.getChoiceIndex = function (choice, choicesLength) {
+    var thisPrototype = Object.getPrototypeOf(this$1);
+    if (thisPrototype && thisPrototype.getChoiceIndex) {
+      var prototypeGetChoiceIndex = (thisPrototype.getChoiceIndex);
+      return (prototypeGetChoiceIndex).call(this$1, choice, choicesLength)
+    }
+
+    // Default (old) getChoiceIndex implementation - english-compatible
+    var defaultImpl = function (_choice, _choicesLength) {
+      _choice = Math.abs(_choice);
+
+      if (_choicesLength === 2) {
+        return _choice
+          ? _choice > 1
+            ? 1
+            : 0
+          : 1
+      }
+
+      return _choice ? Math.min(_choice, 2) : 0
+    };
+
+    if (this$1.locale in this$1.pluralizationRules) {
+      return this$1.pluralizationRules[this$1.locale].apply(this$1, [choice, choicesLength])
+    } else {
+      return defaultImpl(choice, choicesLength)
+    }
+  };
+
+
+  this._exist = function (message, key) {
+    if (!message || !key) { return false }
+    if (!isNull(this$1._path.getPathValue(message, key))) { return true }
+    // fallback for flat key
+    if (message[key]) { return true }
+    return false
+  };
+
+  if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+    Object.keys(messages).forEach(function (locale) {
+      this$1._checkLocaleMessage(locale, this$1._warnHtmlInMessage, messages[locale]);
+    });
+  }
+
+  this._initVM({
+    locale: locale,
+    fallbackLocale: fallbackLocale,
+    messages: messages,
+    dateTimeFormats: dateTimeFormats,
+    numberFormats: numberFormats
+  });
+};
+
+var prototypeAccessors = { vm: { configurable: true },messages: { configurable: true },dateTimeFormats: { configurable: true },numberFormats: { configurable: true },availableLocales: { configurable: true },locale: { configurable: true },fallbackLocale: { configurable: true },formatFallbackMessages: { configurable: true },missing: { configurable: true },formatter: { configurable: true },silentTranslationWarn: { configurable: true },silentFallbackWarn: { configurable: true },preserveDirectiveContent: { configurable: true },warnHtmlInMessage: { configurable: true },postTranslation: { configurable: true } };
+
+VueI18n.prototype._checkLocaleMessage = function _checkLocaleMessage (locale, level, message) {
+  var paths = [];
+
+  var fn = function (level, locale, message, paths) {
+    if (isPlainObject(message)) {
+      Object.keys(message).forEach(function (key) {
+        var val = message[key];
+        if (isPlainObject(val)) {
+          paths.push(key);
+          paths.push('.');
+          fn(level, locale, val, paths);
+          paths.pop();
+          paths.pop();
+        } else {
+          paths.push(key);
+          fn(level, locale, val, paths);
+          paths.pop();
+        }
+      });
+    } else if (isArray(message)) {
+      message.forEach(function (item, index) {
+        if (isPlainObject(item)) {
+          paths.push(("[" + index + "]"));
+          paths.push('.');
+          fn(level, locale, item, paths);
+          paths.pop();
+          paths.pop();
+        } else {
+          paths.push(("[" + index + "]"));
+          fn(level, locale, item, paths);
+          paths.pop();
+        }
+      });
+    } else if (isString(message)) {
+      var ret = htmlTagMatcher.test(message);
+      if (ret) {
+        var msg = "Detected HTML in message '" + message + "' of keypath '" + (paths.join('')) + "' at '" + locale + "'. Consider component interpolation with '<i18n>' to avoid XSS. See https://bit.ly/2ZqJzkp";
+        if (level === 'warn') {
+          warn(msg);
+        } else if (level === 'error') {
+          error(msg);
+        }
+      }
+    }
+  };
+
+  fn(level, locale, message, paths);
+};
+
+VueI18n.prototype._initVM = function _initVM (data) {
+  var silent = Vue.config.silent;
+  Vue.config.silent = true;
+  this._vm = new Vue({ data: data });
+  Vue.config.silent = silent;
+};
+
+VueI18n.prototype.destroyVM = function destroyVM () {
+  this._vm.$destroy();
+};
+
+VueI18n.prototype.subscribeDataChanging = function subscribeDataChanging (vm) {
+  this._dataListeners.push(vm);
+};
+
+VueI18n.prototype.unsubscribeDataChanging = function unsubscribeDataChanging (vm) {
+  remove(this._dataListeners, vm);
+};
+
+VueI18n.prototype.watchI18nData = function watchI18nData () {
+  var self = this;
+  return this._vm.$watch('$data', function () {
+    var i = self._dataListeners.length;
+    while (i--) {
+      Vue.nextTick(function () {
+        self._dataListeners[i] && self._dataListeners[i].$forceUpdate();
+      });
+    }
+  }, { deep: true })
+};
+
+VueI18n.prototype.watchLocale = function watchLocale () {
+  /* istanbul ignore if */
+  if (!this._sync || !this._root) { return null }
+  var target = this._vm;
+  return this._root.$i18n.vm.$watch('locale', function (val) {
+    target.$set(target, 'locale', val);
+    target.$forceUpdate();
+  }, { immediate: true })
+};
+
+VueI18n.prototype.onComponentInstanceCreated = function onComponentInstanceCreated (newI18n) {
+  if (this._componentInstanceCreatedListener) {
+    this._componentInstanceCreatedListener(newI18n, this);
+  }
+};
+
+prototypeAccessors.vm.get = function () { return this._vm };
+
+prototypeAccessors.messages.get = function () { return looseClone(this._getMessages()) };
+prototypeAccessors.dateTimeFormats.get = function () { return looseClone(this._getDateTimeFormats()) };
+prototypeAccessors.numberFormats.get = function () { return looseClone(this._getNumberFormats()) };
+prototypeAccessors.availableLocales.get = function () { return Object.keys(this.messages).sort() };
+
+prototypeAccessors.locale.get = function () { return this._vm.locale };
+prototypeAccessors.locale.set = function (locale) {
+  this._vm.$set(this._vm, 'locale', locale);
+};
+
+prototypeAccessors.fallbackLocale.get = function () { return this._vm.fallbackLocale };
+prototypeAccessors.fallbackLocale.set = function (locale) {
+  this._localeChainCache = {};
+  this._vm.$set(this._vm, 'fallbackLocale', locale);
+};
+
+prototypeAccessors.formatFallbackMessages.get = function () { return this._formatFallbackMessages };
+prototypeAccessors.formatFallbackMessages.set = function (fallback) { this._formatFallbackMessages = fallback; };
+
+prototypeAccessors.missing.get = function () { return this._missing };
+prototypeAccessors.missing.set = function (handler) { this._missing = handler; };
+
+prototypeAccessors.formatter.get = function () { return this._formatter };
+prototypeAccessors.formatter.set = function (formatter) { this._formatter = formatter; };
+
+prototypeAccessors.silentTranslationWarn.get = function () { return this._silentTranslationWarn };
+prototypeAccessors.silentTranslationWarn.set = function (silent) { this._silentTranslationWarn = silent; };
+
+prototypeAccessors.silentFallbackWarn.get = function () { return this._silentFallbackWarn };
+prototypeAccessors.silentFallbackWarn.set = function (silent) { this._silentFallbackWarn = silent; };
+
+prototypeAccessors.preserveDirectiveContent.get = function () { return this._preserveDirectiveContent };
+prototypeAccessors.preserveDirectiveContent.set = function (preserve) { this._preserveDirectiveContent = preserve; };
+
+prototypeAccessors.warnHtmlInMessage.get = function () { return this._warnHtmlInMessage };
+prototypeAccessors.warnHtmlInMessage.set = function (level) {
+    var this$1 = this;
+
+  var orgLevel = this._warnHtmlInMessage;
+  this._warnHtmlInMessage = level;
+  if (orgLevel !== level && (level === 'warn' || level === 'error')) {
+    var messages = this._getMessages();
+    Object.keys(messages).forEach(function (locale) {
+      this$1._checkLocaleMessage(locale, this$1._warnHtmlInMessage, messages[locale]);
+    });
+  }
+};
+
+prototypeAccessors.postTranslation.get = function () { return this._postTranslation };
+prototypeAccessors.postTranslation.set = function (handler) { this._postTranslation = handler; };
+
+VueI18n.prototype._getMessages = function _getMessages () { return this._vm.messages };
+VueI18n.prototype._getDateTimeFormats = function _getDateTimeFormats () { return this._vm.dateTimeFormats };
+VueI18n.prototype._getNumberFormats = function _getNumberFormats () { return this._vm.numberFormats };
+
+VueI18n.prototype._warnDefault = function _warnDefault (locale, key, result, vm, values, interpolateMode) {
+  if (!isNull(result)) { return result }
+  if (this._missing) {
+    var missingRet = this._missing.apply(null, [locale, key, vm, values]);
+    if (isString(missingRet)) {
+      return missingRet
+    }
+  } else {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key)) {
+      warn(
+        "Cannot translate the value of keypath '" + key + "'. " +
+        'Use the value of keypath as default.'
+      );
+    }
+  }
+
+  if (this._formatFallbackMessages) {
+    var parsedArgs = parseArgs.apply(void 0, values);
+    return this._render(key, interpolateMode, parsedArgs.params, key)
+  } else {
+    return key
+  }
+};
+
+VueI18n.prototype._isFallbackRoot = function _isFallbackRoot (val) {
+  return !val && !isNull(this._root) && this._fallbackRoot
+};
+
+VueI18n.prototype._isSilentFallbackWarn = function _isSilentFallbackWarn (key) {
+  return this._silentFallbackWarn instanceof RegExp
+    ? this._silentFallbackWarn.test(key)
+    : this._silentFallbackWarn
+};
+
+VueI18n.prototype._isSilentFallback = function _isSilentFallback (locale, key) {
+  return this._isSilentFallbackWarn(key) && (this._isFallbackRoot() || locale !== this.fallbackLocale)
+};
+
+VueI18n.prototype._isSilentTranslationWarn = function _isSilentTranslationWarn (key) {
+  return this._silentTranslationWarn instanceof RegExp
+    ? this._silentTranslationWarn.test(key)
+    : this._silentTranslationWarn
+};
+
+VueI18n.prototype._interpolate = function _interpolate (
+  locale,
+  message,
+  key,
+  host,
+  interpolateMode,
+  values,
+  visitedLinkStack
+) {
+  if (!message) { return null }
+
+  var pathRet = this._path.getPathValue(message, key);
+  if (isArray(pathRet) || isPlainObject(pathRet)) { return pathRet }
+
+  var ret;
+  if (isNull(pathRet)) {
+    /* istanbul ignore else */
+    if (isPlainObject(message)) {
+      ret = message[key];
+      if (!(isString(ret) || isFunction(ret))) {
+        if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+          warn(("Value of key '" + key + "' is not a string or function !"));
+        }
+        return null
+      }
+    } else {
+      return null
+    }
+  } else {
+    /* istanbul ignore else */
+    if (isString(pathRet) || isFunction(pathRet)) {
+      ret = pathRet;
+    } else {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+        warn(("Value of key '" + key + "' is not a string or function!"));
+      }
+      return null
+    }
+  }
+
+  // Check for the existence of links within the translated string
+  if (isString(ret) && (ret.indexOf('@:') >= 0 || ret.indexOf('@.') >= 0)) {
+    ret = this._link(locale, message, ret, host, 'raw', values, visitedLinkStack);
+  }
+
+  return this._render(ret, interpolateMode, values, key)
+};
+
+VueI18n.prototype._link = function _link (
+  locale,
+  message,
+  str,
+  host,
+  interpolateMode,
+  values,
+  visitedLinkStack
+) {
+  var ret = str;
+
+  // Match all the links within the local
+  // We are going to replace each of
+  // them with its translation
+  var matches = ret.match(linkKeyMatcher);
+  for (var idx in matches) {
+    // ie compatible: filter custom array
+    // prototype method
+    if (!matches.hasOwnProperty(idx)) {
+      continue
+    }
+    var link = matches[idx];
+    var linkKeyPrefixMatches = link.match(linkKeyPrefixMatcher);
+    var linkPrefix = linkKeyPrefixMatches[0];
+      var formatterName = linkKeyPrefixMatches[1];
+
+    // Remove the leading @:, @.case: and the brackets
+    var linkPlaceholder = link.replace(linkPrefix, '').replace(bracketsMatcher, '');
+
+    if (includes(visitedLinkStack, linkPlaceholder)) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn(("Circular reference found. \"" + link + "\" is already visited in the chain of " + (visitedLinkStack.reverse().join(' <- '))));
+      }
+      return ret
+    }
+    visitedLinkStack.push(linkPlaceholder);
+
+    // Translate the link
+    var translated = this._interpolate(
+      locale, message, linkPlaceholder, host,
+      interpolateMode === 'raw' ? 'string' : interpolateMode,
+      interpolateMode === 'raw' ? undefined : values,
+      visitedLinkStack
+    );
+
+    if (this._isFallbackRoot(translated)) {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(linkPlaceholder)) {
+        warn(("Fall back to translate the link placeholder '" + linkPlaceholder + "' with root locale."));
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      var root = this._root.$i18n;
+      translated = root._translate(
+        root._getMessages(), root.locale, root.fallbackLocale,
+        linkPlaceholder, host, interpolateMode, values
+      );
+    }
+    translated = this._warnDefault(
+      locale, linkPlaceholder, translated, host,
+      isArray(values) ? values : [values],
+      interpolateMode
+    );
+
+    if (this._modifiers.hasOwnProperty(formatterName)) {
+      translated = this._modifiers[formatterName](translated);
+    } else if (defaultModifiers.hasOwnProperty(formatterName)) {
+      translated = defaultModifiers[formatterName](translated);
+    }
+
+    visitedLinkStack.pop();
+
+    // Replace the link with the translated
+    ret = !translated ? ret : ret.replace(link, translated);
+  }
+
+  return ret
+};
+
+VueI18n.prototype._createMessageContext = function _createMessageContext (values) {
+  var _list = isArray(values) ? values : [];
+  var _named = isObject(values) ? values : {};
+  var list = function (index) { return _list[index]; };
+  var named = function (key) { return _named[key]; };
+  return {
+    list: list,
+    named: named
+  }
+};
+
+VueI18n.prototype._render = function _render (message, interpolateMode, values, path) {
+  if (isFunction(message)) {
+    return message(this._createMessageContext(values))
+  }
+
+  var ret = this._formatter.interpolate(message, values, path);
+
+  // If the custom formatter refuses to work - apply the default one
+  if (!ret) {
+    ret = defaultFormatter.interpolate(message, values, path);
+  }
+
+  // if interpolateMode is **not** 'string' ('row'),
+  // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
+  return interpolateMode === 'string' && !isString(ret) ? ret.join('') : ret
+};
+
+VueI18n.prototype._appendItemToChain = function _appendItemToChain (chain, item, blocks) {
+  var follow = false;
+  if (!includes(chain, item)) {
+    follow = true;
+    if (item) {
+      follow = item[item.length - 1] !== '!';
+      item = item.replace(/!/g, '');
+      chain.push(item);
+      if (blocks && blocks[item]) {
+        follow = blocks[item];
+      }
+    }
+  }
+  return follow
+};
+
+VueI18n.prototype._appendLocaleToChain = function _appendLocaleToChain (chain, locale, blocks) {
+  var follow;
+  var tokens = locale.split('-');
+  do {
+    var item = tokens.join('-');
+    follow = this._appendItemToChain(chain, item, blocks);
+    tokens.splice(-1, 1);
+  } while (tokens.length && (follow === true))
+  return follow
+};
+
+VueI18n.prototype._appendBlockToChain = function _appendBlockToChain (chain, block, blocks) {
+  var follow = true;
+  for (var i = 0; (i < block.length) && (isBoolean(follow)); i++) {
+    var locale = block[i];
+    if (isString(locale)) {
+      follow = this._appendLocaleToChain(chain, locale, blocks);
+    }
+  }
+  return follow
+};
+
+VueI18n.prototype._getLocaleChain = function _getLocaleChain (start, fallbackLocale) {
+  if (start === '') { return [] }
+
+  if (!this._localeChainCache) {
+    this._localeChainCache = {};
+  }
+
+  var chain = this._localeChainCache[start];
+  if (!chain) {
+    if (!fallbackLocale) {
+      fallbackLocale = this.fallbackLocale;
+    }
+    chain = [];
+
+    // first block defined by start
+    var block = [start];
+
+    // while any intervening block found
+    while (isArray(block)) {
+      block = this._appendBlockToChain(
+        chain,
+        block,
+        fallbackLocale
+      );
+    }
+
+    // last block defined by default
+    var defaults;
+    if (isArray(fallbackLocale)) {
+      defaults = fallbackLocale;
+    } else if (isObject(fallbackLocale)) {
+      /* $FlowFixMe */
+      if (fallbackLocale['default']) {
+        defaults = fallbackLocale['default'];
+      } else {
+        defaults = null;
+      }
+    } else {
+      defaults = fallbackLocale;
+    }
+
+    // convert defaults to array
+    if (isString(defaults)) {
+      block = [defaults];
+    } else {
+      block = defaults;
+    }
+    if (block) {
+      this._appendBlockToChain(
+        chain,
+        block,
+        null
+      );
+    }
+    this._localeChainCache[start] = chain;
+  }
+  return chain
+};
+
+VueI18n.prototype._translate = function _translate (
+  messages,
+  locale,
+  fallback,
+  key,
+  host,
+  interpolateMode,
+  args
+) {
+  var chain = this._getLocaleChain(locale, fallback);
+  var res;
+  for (var i = 0; i < chain.length; i++) {
+    var step = chain[i];
+    res =
+      this._interpolate(step, messages[step], key, host, interpolateMode, args, [key]);
+    if (!isNull(res)) {
+      if (step !== locale && process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(("Fall back to translate the keypath '" + key + "' with '" + step + "' locale."));
+      }
+      return res
+    }
+  }
+  return null
+};
+
+VueI18n.prototype._t = function _t (key, _locale, messages, host) {
+    var ref;
+
+    var values = [], len = arguments.length - 4;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 4 ];
+  if (!key) { return '' }
+
+  var parsedArgs = parseArgs.apply(void 0, values);
+  var locale = parsedArgs.locale || _locale;
+
+  var ret = this._translate(
+    messages, locale, this.fallbackLocale, key,
+    host, 'string', parsedArgs.params
+  );
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+      warn(("Fall back to translate the keypath '" + key + "' with root locale."));
+    }
+    /* istanbul ignore if */
+    if (!this._root) { throw Error('unexpected error') }
+    return (ref = this._root).$t.apply(ref, [ key ].concat( values ))
+  } else {
+    ret = this._warnDefault(locale, key, ret, host, values, 'string');
+    if (this._postTranslation && ret !== null && ret !== undefined) {
+      ret = this._postTranslation(ret, key);
+    }
+    return ret
+  }
+};
+
+VueI18n.prototype.t = function t (key) {
+    var ref;
+
+    var values = [], len = arguments.length - 1;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 1 ];
+  return (ref = this)._t.apply(ref, [ key, this.locale, this._getMessages(), null ].concat( values ))
+};
+
+VueI18n.prototype._i = function _i (key, locale, messages, host, values) {
+  var ret =
+    this._translate(messages, locale, this.fallbackLocale, key, host, 'raw', values);
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key)) {
+      warn(("Fall back to interpolate the keypath '" + key + "' with root locale."));
+    }
+    if (!this._root) { throw Error('unexpected error') }
+    return this._root.$i18n.i(key, locale, values)
+  } else {
+    return this._warnDefault(locale, key, ret, host, [values], 'raw')
+  }
+};
+
+VueI18n.prototype.i = function i (key, locale, values) {
+  /* istanbul ignore if */
+  if (!key) { return '' }
+
+  if (!isString(locale)) {
+    locale = this.locale;
+  }
+
+  return this._i(key, locale, this._getMessages(), null, values)
+};
+
+VueI18n.prototype._tc = function _tc (
+  key,
+  _locale,
+  messages,
+  host,
+  choice
+) {
+    var ref;
+
+    var values = [], len = arguments.length - 5;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 5 ];
+  if (!key) { return '' }
+  if (choice === undefined) {
+    choice = 1;
+  }
+
+  var predefined = { 'count': choice, 'n': choice };
+  var parsedArgs = parseArgs.apply(void 0, values);
+  parsedArgs.params = Object.assign(predefined, parsedArgs.params);
+  values = parsedArgs.locale === null ? [parsedArgs.params] : [parsedArgs.locale, parsedArgs.params];
+  return this.fetchChoice((ref = this)._t.apply(ref, [ key, _locale, messages, host ].concat( values )), choice)
+};
+
+VueI18n.prototype.fetchChoice = function fetchChoice (message, choice) {
+  /* istanbul ignore if */
+  if (!message && !isString(message)) { return null }
+  var choices = message.split('|');
+
+  choice = this.getChoiceIndex(choice, choices.length);
+  if (!choices[choice]) { return message }
+  return choices[choice].trim()
+};
+
+VueI18n.prototype.tc = function tc (key, choice) {
+    var ref;
+
+    var values = [], len = arguments.length - 2;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 2 ];
+  return (ref = this)._tc.apply(ref, [ key, this.locale, this._getMessages(), null, choice ].concat( values ))
+};
+
+VueI18n.prototype._te = function _te (key, locale, messages) {
+    var args = [], len = arguments.length - 3;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 3 ];
+
+  var _locale = parseArgs.apply(void 0, args).locale || locale;
+  return this._exist(messages[_locale], key)
+};
+
+VueI18n.prototype.te = function te (key, locale) {
+  return this._te(key, this.locale, this._getMessages(), locale)
+};
+
+VueI18n.prototype.getLocaleMessage = function getLocaleMessage (locale) {
+  return looseClone(this._vm.messages[locale] || {})
+};
+
+VueI18n.prototype.setLocaleMessage = function setLocaleMessage (locale, message) {
+  if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+    this._checkLocaleMessage(locale, this._warnHtmlInMessage, message);
+  }
+  this._vm.$set(this._vm.messages, locale, message);
+};
+
+VueI18n.prototype.mergeLocaleMessage = function mergeLocaleMessage (locale, message) {
+  if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+    this._checkLocaleMessage(locale, this._warnHtmlInMessage, message);
+  }
+  this._vm.$set(this._vm.messages, locale, merge({}, this._vm.messages[locale] || {}, message));
+};
+
+VueI18n.prototype.getDateTimeFormat = function getDateTimeFormat (locale) {
+  return looseClone(this._vm.dateTimeFormats[locale] || {})
+};
+
+VueI18n.prototype.setDateTimeFormat = function setDateTimeFormat (locale, format) {
+  this._vm.$set(this._vm.dateTimeFormats, locale, format);
+  this._clearDateTimeFormat(locale, format);
+};
+
+VueI18n.prototype.mergeDateTimeFormat = function mergeDateTimeFormat (locale, format) {
+  this._vm.$set(this._vm.dateTimeFormats, locale, merge(this._vm.dateTimeFormats[locale] || {}, format));
+  this._clearDateTimeFormat(locale, format);
+};
+
+VueI18n.prototype._clearDateTimeFormat = function _clearDateTimeFormat (locale, format) {
+  for (var key in format) {
+    var id = locale + "__" + key;
+
+    if (!this._dateTimeFormatters.hasOwnProperty(id)) {
+      continue
+    }
+
+    delete this._dateTimeFormatters[id];
+  }
+};
+
+VueI18n.prototype._localizeDateTime = function _localizeDateTime (
+  value,
+  locale,
+  fallback,
+  dateTimeFormats,
+  key
+) {
+  var _locale = locale;
+  var formats = dateTimeFormats[_locale];
+
+  var chain = this._getLocaleChain(locale, fallback);
+  for (var i = 0; i < chain.length; i++) {
+    var current = _locale;
+    var step = chain[i];
+    formats = dateTimeFormats[step];
+    _locale = step;
+    // fallback locale
+    if (isNull(formats) || isNull(formats[key])) {
+      if (step !== locale && process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(("Fall back to '" + step + "' datetime formats from '" + current + "' datetime formats."));
+      }
+    } else {
+      break
+    }
+  }
+
+  if (isNull(formats) || isNull(formats[key])) {
+    return null
+  } else {
+    var format = formats[key];
+    var id = _locale + "__" + key;
+    var formatter = this._dateTimeFormatters[id];
+    if (!formatter) {
+      formatter = this._dateTimeFormatters[id] = new Intl.DateTimeFormat(_locale, format);
+    }
+    return formatter.format(value)
+  }
+};
+
+VueI18n.prototype._d = function _d (value, locale, key) {
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && !VueI18n.availabilities.dateTimeFormat) {
+    warn('Cannot format a Date value due to not supported Intl.DateTimeFormat.');
+    return ''
+  }
+
+  if (!key) {
+    return new Intl.DateTimeFormat(locale).format(value)
+  }
+
+  var ret =
+    this._localizeDateTime(value, locale, this.fallbackLocale, this._getDateTimeFormats(), key);
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+      warn(("Fall back to datetime localization of root: key '" + key + "'."));
+    }
+    /* istanbul ignore if */
+    if (!this._root) { throw Error('unexpected error') }
+    return this._root.$i18n.d(value, key, locale)
+  } else {
+    return ret || ''
+  }
+};
+
+VueI18n.prototype.d = function d (value) {
+    var args = [], len = arguments.length - 1;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+
+  var locale = this.locale;
+  var key = null;
+
+  if (args.length === 1) {
+    if (isString(args[0])) {
+      key = args[0];
+    } else if (isObject(args[0])) {
+      if (args[0].locale) {
+        locale = args[0].locale;
+      }
+      if (args[0].key) {
+        key = args[0].key;
+      }
+    }
+  } else if (args.length === 2) {
+    if (isString(args[0])) {
+      key = args[0];
+    }
+    if (isString(args[1])) {
+      locale = args[1];
+    }
+  }
+
+  return this._d(value, locale, key)
+};
+
+VueI18n.prototype.getNumberFormat = function getNumberFormat (locale) {
+  return looseClone(this._vm.numberFormats[locale] || {})
+};
+
+VueI18n.prototype.setNumberFormat = function setNumberFormat (locale, format) {
+  this._vm.$set(this._vm.numberFormats, locale, format);
+  this._clearNumberFormat(locale, format);
+};
+
+VueI18n.prototype.mergeNumberFormat = function mergeNumberFormat (locale, format) {
+  this._vm.$set(this._vm.numberFormats, locale, merge(this._vm.numberFormats[locale] || {}, format));
+  this._clearNumberFormat(locale, format);
+};
+
+VueI18n.prototype._clearNumberFormat = function _clearNumberFormat (locale, format) {
+  for (var key in format) {
+    var id = locale + "__" + key;
+
+    if (!this._numberFormatters.hasOwnProperty(id)) {
+      continue
+    }
+
+    delete this._numberFormatters[id];
+  }
+};
+
+VueI18n.prototype._getNumberFormatter = function _getNumberFormatter (
+  value,
+  locale,
+  fallback,
+  numberFormats,
+  key,
+  options
+) {
+  var _locale = locale;
+  var formats = numberFormats[_locale];
+
+  var chain = this._getLocaleChain(locale, fallback);
+  for (var i = 0; i < chain.length; i++) {
+    var current = _locale;
+    var step = chain[i];
+    formats = numberFormats[step];
+    _locale = step;
+    // fallback locale
+    if (isNull(formats) || isNull(formats[key])) {
+      if (step !== locale && process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(("Fall back to '" + step + "' number formats from '" + current + "' number formats."));
+      }
+    } else {
+      break
+    }
+  }
+
+  if (isNull(formats) || isNull(formats[key])) {
+    return null
+  } else {
+    var format = formats[key];
+
+    var formatter;
+    if (options) {
+      // If options specified - create one time number formatter
+      formatter = new Intl.NumberFormat(_locale, Object.assign({}, format, options));
+    } else {
+      var id = _locale + "__" + key;
+      formatter = this._numberFormatters[id];
+      if (!formatter) {
+        formatter = this._numberFormatters[id] = new Intl.NumberFormat(_locale, format);
+      }
+    }
+    return formatter
+  }
+};
+
+VueI18n.prototype._n = function _n (value, locale, key, options) {
+  /* istanbul ignore if */
+  if (!VueI18n.availabilities.numberFormat) {
+    if (process.env.NODE_ENV !== 'production') {
+      warn('Cannot format a Number value due to not supported Intl.NumberFormat.');
+    }
+    return ''
+  }
+
+  if (!key) {
+    var nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options);
+    return nf.format(value)
+  }
+
+  var formatter = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
+  var ret = formatter && formatter.format(value);
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+      warn(("Fall back to number localization of root: key '" + key + "'."));
+    }
+    /* istanbul ignore if */
+    if (!this._root) { throw Error('unexpected error') }
+    return this._root.$i18n.n(value, Object.assign({}, { key: key, locale: locale }, options))
+  } else {
+    return ret || ''
+  }
+};
+
+VueI18n.prototype.n = function n (value) {
+    var args = [], len = arguments.length - 1;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+
+  var locale = this.locale;
+  var key = null;
+  var options = null;
+
+  if (args.length === 1) {
+    if (isString(args[0])) {
+      key = args[0];
+    } else if (isObject(args[0])) {
+      if (args[0].locale) {
+        locale = args[0].locale;
+      }
+      if (args[0].key) {
+        key = args[0].key;
+      }
+
+      // Filter out number format options only
+      options = Object.keys(args[0]).reduce(function (acc, key) {
+          var obj;
+
+        if (includes(numberFormatKeys, key)) {
+          return Object.assign({}, acc, ( obj = {}, obj[key] = args[0][key], obj ))
+        }
+        return acc
+      }, null);
+    }
+  } else if (args.length === 2) {
+    if (isString(args[0])) {
+      key = args[0];
+    }
+    if (isString(args[1])) {
+      locale = args[1];
+    }
+  }
+
+  return this._n(value, locale, key, options)
+};
+
+VueI18n.prototype._ntp = function _ntp (value, locale, key, options) {
+  /* istanbul ignore if */
+  if (!VueI18n.availabilities.numberFormat) {
+    if (process.env.NODE_ENV !== 'production') {
+      warn('Cannot format to parts a Number value due to not supported Intl.NumberFormat.');
+    }
+    return []
+  }
+
+  if (!key) {
+    var nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options);
+    return nf.formatToParts(value)
+  }
+
+  var formatter = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
+  var ret = formatter && formatter.formatToParts(value);
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key)) {
+      warn(("Fall back to format number to parts of root: key '" + key + "' ."));
+    }
+    /* istanbul ignore if */
+    if (!this._root) { throw Error('unexpected error') }
+    return this._root.$i18n._ntp(value, locale, key, options)
+  } else {
+    return ret || []
+  }
+};
+
+Object.defineProperties( VueI18n.prototype, prototypeAccessors );
+
+var availabilities;
+// $FlowFixMe
+Object.defineProperty(VueI18n, 'availabilities', {
+  get: function get () {
+    if (!availabilities) {
+      var intlDefined = typeof Intl !== 'undefined';
+      availabilities = {
+        dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
+        numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
+      };
+    }
+
+    return availabilities
+  }
+});
+
+VueI18n.install = install;
+VueI18n.version = '8.21.0';
+
+module.exports = VueI18n;

+ 2104 - 0
plugin/vue-i18n/dist/vue-i18n.esm.browser.js

@@ -0,0 +1,2104 @@
+/*  */
+
+/**
+ * constants
+ */
+
+const numberFormatKeys = [
+  'style',
+  'currency',
+  'currencyDisplay',
+  'useGrouping',
+  'minimumIntegerDigits',
+  'minimumFractionDigits',
+  'maximumFractionDigits',
+  'minimumSignificantDigits',
+  'maximumSignificantDigits',
+  'localeMatcher',
+  'formatMatcher',
+  'unit'
+];
+
+/**
+ * utilities
+ */
+
+function warn (msg, err) {
+  if (typeof console !== 'undefined') {
+    console.warn('[vue-i18n] ' + msg);
+    /* istanbul ignore if */
+    if (err) {
+      console.warn(err.stack);
+    }
+  }
+}
+
+function error (msg, err) {
+  if (typeof console !== 'undefined') {
+    console.error('[vue-i18n] ' + msg);
+    /* istanbul ignore if */
+    if (err) {
+      console.error(err.stack);
+    }
+  }
+}
+
+const isArray = Array.isArray;
+
+function isObject (obj) {
+  return obj !== null && typeof obj === 'object'
+}
+
+function isBoolean (val) {
+  return typeof val === 'boolean'
+}
+
+function isString (val) {
+  return typeof val === 'string'
+}
+
+const toString = Object.prototype.toString;
+const OBJECT_STRING = '[object Object]';
+function isPlainObject (obj) {
+  return toString.call(obj) === OBJECT_STRING
+}
+
+function isNull (val) {
+  return val === null || val === undefined
+}
+
+function isFunction (val) {
+  return typeof val === 'function'
+}
+
+function parseArgs (...args) {
+  let locale = null;
+  let params = null;
+  if (args.length === 1) {
+    if (isObject(args[0]) || isArray(args[0])) {
+      params = args[0];
+    } else if (typeof args[0] === 'string') {
+      locale = args[0];
+    }
+  } else if (args.length === 2) {
+    if (typeof args[0] === 'string') {
+      locale = args[0];
+    }
+    /* istanbul ignore if */
+    if (isObject(args[1]) || isArray(args[1])) {
+      params = args[1];
+    }
+  }
+
+  return { locale, params }
+}
+
+function looseClone (obj) {
+  return JSON.parse(JSON.stringify(obj))
+}
+
+function remove (arr, item) {
+  if (arr.length) {
+    const index = arr.indexOf(item);
+    if (index > -1) {
+      return arr.splice(index, 1)
+    }
+  }
+}
+
+function includes (arr, item) {
+  return !!~arr.indexOf(item)
+}
+
+const hasOwnProperty = Object.prototype.hasOwnProperty;
+function hasOwn (obj, key) {
+  return hasOwnProperty.call(obj, key)
+}
+
+function merge (target) {
+  const output = Object(target);
+  for (let i = 1; i < arguments.length; i++) {
+    const source = arguments[i];
+    if (source !== undefined && source !== null) {
+      let key;
+      for (key in source) {
+        if (hasOwn(source, key)) {
+          if (isObject(source[key])) {
+            output[key] = merge(output[key], source[key]);
+          } else {
+            output[key] = source[key];
+          }
+        }
+      }
+    }
+  }
+  return output
+}
+
+function looseEqual (a, b) {
+  if (a === b) { return true }
+  const isObjectA = isObject(a);
+  const isObjectB = isObject(b);
+  if (isObjectA && isObjectB) {
+    try {
+      const isArrayA = isArray(a);
+      const isArrayB = isArray(b);
+      if (isArrayA && isArrayB) {
+        return a.length === b.length && a.every((e, i) => {
+          return looseEqual(e, b[i])
+        })
+      } else if (!isArrayA && !isArrayB) {
+        const keysA = Object.keys(a);
+        const keysB = Object.keys(b);
+        return keysA.length === keysB.length && keysA.every((key) => {
+          return looseEqual(a[key], b[key])
+        })
+      } else {
+        /* istanbul ignore next */
+        return false
+      }
+    } catch (e) {
+      /* istanbul ignore next */
+      return false
+    }
+  } else if (!isObjectA && !isObjectB) {
+    return String(a) === String(b)
+  } else {
+    return false
+  }
+}
+
+/*  */
+
+function extend (Vue) {
+  if (!Vue.prototype.hasOwnProperty('$i18n')) {
+    // $FlowFixMe
+    Object.defineProperty(Vue.prototype, '$i18n', {
+      get () { return this._i18n }
+    });
+  }
+
+  Vue.prototype.$t = function (key, ...values) {
+    const i18n = this.$i18n;
+    return i18n._t(key, i18n.locale, i18n._getMessages(), this, ...values)
+  };
+
+  Vue.prototype.$tc = function (key, choice, ...values) {
+    const i18n = this.$i18n;
+    return i18n._tc(key, i18n.locale, i18n._getMessages(), this, choice, ...values)
+  };
+
+  Vue.prototype.$te = function (key, locale) {
+    const i18n = this.$i18n;
+    return i18n._te(key, i18n.locale, i18n._getMessages(), locale)
+  };
+
+  Vue.prototype.$d = function (value, ...args) {
+    return this.$i18n.d(value, ...args)
+  };
+
+  Vue.prototype.$n = function (value, ...args) {
+    return this.$i18n.n(value, ...args)
+  };
+}
+
+/*  */
+
+var mixin = {
+  beforeCreate () {
+    const options = this.$options;
+    options.i18n = options.i18n || (options.__i18n ? {} : null);
+
+    if (options.i18n) {
+      if (options.i18n instanceof VueI18n) {
+        // init locale messages via custom blocks
+        if (options.__i18n) {
+          try {
+            let localeMessages = {};
+            options.__i18n.forEach(resource => {
+              localeMessages = merge(localeMessages, JSON.parse(resource));
+            });
+            Object.keys(localeMessages).forEach((locale) => {
+              options.i18n.mergeLocaleMessage(locale, localeMessages[locale]);
+            });
+          } catch (e) {
+            {
+              error(`Cannot parse locale messages via custom blocks.`, e);
+            }
+          }
+        }
+        this._i18n = options.i18n;
+        this._i18nWatcher = this._i18n.watchI18nData();
+      } else if (isPlainObject(options.i18n)) {
+        const rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
+          ? this.$root.$i18n
+          : null;
+        // component local i18n
+        if (rootI18n) {
+          options.i18n.root = this.$root;
+          options.i18n.formatter = rootI18n.formatter;
+          options.i18n.fallbackLocale = rootI18n.fallbackLocale;
+          options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages;
+          options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn;
+          options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn;
+          options.i18n.pluralizationRules = rootI18n.pluralizationRules;
+          options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent;
+        }
+
+        // init locale messages via custom blocks
+        if (options.__i18n) {
+          try {
+            let localeMessages = {};
+            options.__i18n.forEach(resource => {
+              localeMessages = merge(localeMessages, JSON.parse(resource));
+            });
+            options.i18n.messages = localeMessages;
+          } catch (e) {
+            {
+              warn(`Cannot parse locale messages via custom blocks.`, e);
+            }
+          }
+        }
+
+        const { sharedMessages } = options.i18n;
+        if (sharedMessages && isPlainObject(sharedMessages)) {
+          options.i18n.messages = merge(options.i18n.messages, sharedMessages);
+        }
+
+        this._i18n = new VueI18n(options.i18n);
+        this._i18nWatcher = this._i18n.watchI18nData();
+
+        if (options.i18n.sync === undefined || !!options.i18n.sync) {
+          this._localeWatcher = this.$i18n.watchLocale();
+        }
+
+        if (rootI18n) {
+          rootI18n.onComponentInstanceCreated(this._i18n);
+        }
+      } else {
+        {
+          warn(`Cannot be interpreted 'i18n' option.`);
+        }
+      }
+    } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+      // root i18n
+      this._i18n = this.$root.$i18n;
+    } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+      // parent i18n
+      this._i18n = options.parent.$i18n;
+    }
+  },
+
+  beforeMount () {
+    const options = this.$options;
+    options.i18n = options.i18n || (options.__i18n ? {} : null);
+
+    if (options.i18n) {
+      if (options.i18n instanceof VueI18n) {
+        // init locale messages via custom blocks
+        this._i18n.subscribeDataChanging(this);
+        this._subscribing = true;
+      } else if (isPlainObject(options.i18n)) {
+        this._i18n.subscribeDataChanging(this);
+        this._subscribing = true;
+      } else {
+        {
+          warn(`Cannot be interpreted 'i18n' option.`);
+        }
+      }
+    } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+      this._i18n.subscribeDataChanging(this);
+      this._subscribing = true;
+    } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+      this._i18n.subscribeDataChanging(this);
+      this._subscribing = true;
+    }
+  },
+
+  beforeDestroy () {
+    if (!this._i18n) { return }
+
+    const self = this;
+    this.$nextTick(() => {
+      if (self._subscribing) {
+        self._i18n.unsubscribeDataChanging(self);
+        delete self._subscribing;
+      }
+
+      if (self._i18nWatcher) {
+        self._i18nWatcher();
+        self._i18n.destroyVM();
+        delete self._i18nWatcher;
+      }
+
+      if (self._localeWatcher) {
+        self._localeWatcher();
+        delete self._localeWatcher;
+      }
+    });
+  }
+};
+
+/*  */
+
+var interpolationComponent = {
+  name: 'i18n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    path: {
+      type: String,
+      required: true
+    },
+    locale: {
+      type: String
+    },
+    places: {
+      type: [Array, Object]
+    }
+  },
+  render (h, { data, parent, props, slots }) {
+    const { $i18n } = parent;
+    if (!$i18n) {
+      {
+        warn('Cannot find VueI18n instance!');
+      }
+      return
+    }
+
+    const { path, locale, places } = props;
+    const params = slots();
+    const children = $i18n.i(
+      path,
+      locale,
+      onlyHasDefaultPlace(params) || places
+        ? useLegacyPlaces(params.default, places)
+        : params
+    );
+
+    const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span';
+    return tag ? h(tag, data, children) : children
+  }
+};
+
+function onlyHasDefaultPlace (params) {
+  let prop;
+  for (prop in params) {
+    if (prop !== 'default') { return false }
+  }
+  return Boolean(prop)
+}
+
+function useLegacyPlaces (children, places) {
+  const params = places ? createParamsFromPlaces(places) : {};
+
+  if (!children) { return params }
+
+  // Filter empty text nodes
+  children = children.filter(child => {
+    return child.tag || child.text.trim() !== ''
+  });
+
+  const everyPlace = children.every(vnodeHasPlaceAttribute);
+  if (everyPlace) {
+    warn('`place` attribute is deprecated in next major version. Please switch to Vue slots.');
+  }
+
+  return children.reduce(
+    everyPlace ? assignChildPlace : assignChildIndex,
+    params
+  )
+}
+
+function createParamsFromPlaces (places) {
+  {
+    warn('`places` prop is deprecated in next major version. Please switch to Vue slots.');
+  }
+
+  return Array.isArray(places)
+    ? places.reduce(assignChildIndex, {})
+    : Object.assign({}, places)
+}
+
+function assignChildPlace (params, child) {
+  if (child.data && child.data.attrs && child.data.attrs.place) {
+    params[child.data.attrs.place] = child;
+  }
+  return params
+}
+
+function assignChildIndex (params, child, index) {
+  params[index] = child;
+  return params
+}
+
+function vnodeHasPlaceAttribute (vnode) {
+  return Boolean(vnode.data && vnode.data.attrs && vnode.data.attrs.place)
+}
+
+/*  */
+
+var numberComponent = {
+  name: 'i18n-n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    value: {
+      type: Number,
+      required: true
+    },
+    format: {
+      type: [String, Object]
+    },
+    locale: {
+      type: String
+    }
+  },
+  render (h, { props, parent, data }) {
+    const i18n = parent.$i18n;
+
+    if (!i18n) {
+      {
+        warn('Cannot find VueI18n instance!');
+      }
+      return null
+    }
+
+    let key = null;
+    let options = null;
+
+    if (isString(props.format)) {
+      key = props.format;
+    } else if (isObject(props.format)) {
+      if (props.format.key) {
+        key = props.format.key;
+      }
+
+      // Filter out number format options only
+      options = Object.keys(props.format).reduce((acc, prop) => {
+        if (includes(numberFormatKeys, prop)) {
+          return Object.assign({}, acc, { [prop]: props.format[prop] })
+        }
+        return acc
+      }, null);
+    }
+
+    const locale = props.locale || i18n.locale;
+    const parts = i18n._ntp(props.value, locale, key, options);
+
+    const values = parts.map((part, index) => {
+      const slot = data.scopedSlots && data.scopedSlots[part.type];
+      return slot ? slot({ [part.type]: part.value, index, parts }) : part.value
+    });
+
+    const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span';
+    return tag
+      ? h(tag, {
+        attrs: data.attrs,
+        'class': data['class'],
+        staticClass: data.staticClass
+      }, values)
+      : values
+  }
+};
+
+/*  */
+
+function bind (el, binding, vnode) {
+  if (!assert(el, vnode)) { return }
+
+  t(el, binding, vnode);
+}
+
+function update (el, binding, vnode, oldVNode) {
+  if (!assert(el, vnode)) { return }
+
+  const i18n = vnode.context.$i18n;
+  if (localeEqual(el, vnode) &&
+    (looseEqual(binding.value, binding.oldValue) &&
+     looseEqual(el._localeMessage, i18n.getLocaleMessage(i18n.locale)))) { return }
+
+  t(el, binding, vnode);
+}
+
+function unbind (el, binding, vnode, oldVNode) {
+  const vm = vnode.context;
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context');
+    return
+  }
+
+  const i18n = vnode.context.$i18n || {};
+  if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
+    el.textContent = '';
+  }
+  el._vt = undefined;
+  delete el['_vt'];
+  el._locale = undefined;
+  delete el['_locale'];
+  el._localeMessage = undefined;
+  delete el['_localeMessage'];
+}
+
+function assert (el, vnode) {
+  const vm = vnode.context;
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context');
+    return false
+  }
+
+  if (!vm.$i18n) {
+    warn('VueI18n instance does not exists in Vue instance');
+    return false
+  }
+
+  return true
+}
+
+function localeEqual (el, vnode) {
+  const vm = vnode.context;
+  return el._locale === vm.$i18n.locale
+}
+
+function t (el, binding, vnode) {
+  const value = binding.value;
+
+  const { path, locale, args, choice } = parseValue(value);
+  if (!path && !locale && !args) {
+    warn('value type not supported');
+    return
+  }
+
+  if (!path) {
+    warn('`path` is required in v-t directive');
+    return
+  }
+
+  const vm = vnode.context;
+  if (choice != null) {
+    el._vt = el.textContent = vm.$i18n.tc(path, choice, ...makeParams(locale, args));
+  } else {
+    el._vt = el.textContent = vm.$i18n.t(path, ...makeParams(locale, args));
+  }
+  el._locale = vm.$i18n.locale;
+  el._localeMessage = vm.$i18n.getLocaleMessage(vm.$i18n.locale);
+}
+
+function parseValue (value) {
+  let path;
+  let locale;
+  let args;
+  let choice;
+
+  if (isString(value)) {
+    path = value;
+  } else if (isPlainObject(value)) {
+    path = value.path;
+    locale = value.locale;
+    args = value.args;
+    choice = value.choice;
+  }
+
+  return { path, locale, args, choice }
+}
+
+function makeParams (locale, args) {
+  const params = [];
+
+  locale && params.push(locale);
+  if (args && (Array.isArray(args) || isPlainObject(args))) {
+    params.push(args);
+  }
+
+  return params
+}
+
+let Vue;
+
+function install (_Vue) {
+  /* istanbul ignore if */
+  if (install.installed && _Vue === Vue) {
+    warn('already installed.');
+    return
+  }
+  install.installed = true;
+
+  Vue = _Vue;
+
+  const version = (Vue.version && Number(Vue.version.split('.')[0])) || -1;
+  /* istanbul ignore if */
+  if (version < 2) {
+    warn(`vue-i18n (${install.version}) need to use Vue 2.0 or later (Vue: ${Vue.version}).`);
+    return
+  }
+
+  extend(Vue);
+  Vue.mixin(mixin);
+  Vue.directive('t', { bind, update, unbind });
+  Vue.component(interpolationComponent.name, interpolationComponent);
+  Vue.component(numberComponent.name, numberComponent);
+
+  // use simple mergeStrategies to prevent i18n instance lose '__proto__'
+  const strats = Vue.config.optionMergeStrategies;
+  strats.i18n = function (parentVal, childVal) {
+    return childVal === undefined
+      ? parentVal
+      : childVal
+  };
+}
+
+/*  */
+
+class BaseFormatter {
+  
+
+  constructor () {
+    this._caches = Object.create(null);
+  }
+
+  interpolate (message, values) {
+    if (!values) {
+      return [message]
+    }
+    let tokens = this._caches[message];
+    if (!tokens) {
+      tokens = parse(message);
+      this._caches[message] = tokens;
+    }
+    return compile(tokens, values)
+  }
+}
+
+
+
+const RE_TOKEN_LIST_VALUE = /^(?:\d)+/;
+const RE_TOKEN_NAMED_VALUE = /^(?:\w)+/;
+
+function parse (format) {
+  const tokens = [];
+  let position = 0;
+
+  let text = '';
+  while (position < format.length) {
+    let char = format[position++];
+    if (char === '{') {
+      if (text) {
+        tokens.push({ type: 'text', value: text });
+      }
+
+      text = '';
+      let sub = '';
+      char = format[position++];
+      while (char !== undefined && char !== '}') {
+        sub += char;
+        char = format[position++];
+      }
+      const isClosed = char === '}';
+
+      const type = RE_TOKEN_LIST_VALUE.test(sub)
+        ? 'list'
+        : isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
+          ? 'named'
+          : 'unknown';
+      tokens.push({ value: sub, type });
+    } else if (char === '%') {
+      // when found rails i18n syntax, skip text capture
+      if (format[(position)] !== '{') {
+        text += char;
+      }
+    } else {
+      text += char;
+    }
+  }
+
+  text && tokens.push({ type: 'text', value: text });
+
+  return tokens
+}
+
+function compile (tokens, values) {
+  const compiled = [];
+  let index = 0;
+
+  const mode = Array.isArray(values)
+    ? 'list'
+    : isObject(values)
+      ? 'named'
+      : 'unknown';
+  if (mode === 'unknown') { return compiled }
+
+  while (index < tokens.length) {
+    const token = tokens[index];
+    switch (token.type) {
+      case 'text':
+        compiled.push(token.value);
+        break
+      case 'list':
+        compiled.push(values[parseInt(token.value, 10)]);
+        break
+      case 'named':
+        if (mode === 'named') {
+          compiled.push((values)[token.value]);
+        } else {
+          {
+            warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`);
+          }
+        }
+        break
+      case 'unknown':
+        {
+          warn(`Detect 'unknown' type of token!`);
+        }
+        break
+    }
+    index++;
+  }
+
+  return compiled
+}
+
+/*  */
+
+/**
+ *  Path parser
+ *  - Inspired:
+ *    Vue.js Path parser
+ */
+
+// actions
+const APPEND = 0;
+const PUSH = 1;
+const INC_SUB_PATH_DEPTH = 2;
+const PUSH_SUB_PATH = 3;
+
+// states
+const BEFORE_PATH = 0;
+const IN_PATH = 1;
+const BEFORE_IDENT = 2;
+const IN_IDENT = 3;
+const IN_SUB_PATH = 4;
+const IN_SINGLE_QUOTE = 5;
+const IN_DOUBLE_QUOTE = 6;
+const AFTER_PATH = 7;
+const ERROR = 8;
+
+const pathStateMachine = [];
+
+pathStateMachine[BEFORE_PATH] = {
+  'ws': [BEFORE_PATH],
+  'ident': [IN_IDENT, APPEND],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+};
+
+pathStateMachine[IN_PATH] = {
+  'ws': [IN_PATH],
+  '.': [BEFORE_IDENT],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+};
+
+pathStateMachine[BEFORE_IDENT] = {
+  'ws': [BEFORE_IDENT],
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND]
+};
+
+pathStateMachine[IN_IDENT] = {
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND],
+  'ws': [IN_PATH, PUSH],
+  '.': [BEFORE_IDENT, PUSH],
+  '[': [IN_SUB_PATH, PUSH],
+  'eof': [AFTER_PATH, PUSH]
+};
+
+pathStateMachine[IN_SUB_PATH] = {
+  "'": [IN_SINGLE_QUOTE, APPEND],
+  '"': [IN_DOUBLE_QUOTE, APPEND],
+  '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
+  ']': [IN_PATH, PUSH_SUB_PATH],
+  'eof': ERROR,
+  'else': [IN_SUB_PATH, APPEND]
+};
+
+pathStateMachine[IN_SINGLE_QUOTE] = {
+  "'": [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_SINGLE_QUOTE, APPEND]
+};
+
+pathStateMachine[IN_DOUBLE_QUOTE] = {
+  '"': [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_DOUBLE_QUOTE, APPEND]
+};
+
+/**
+ * Check if an expression is a literal value.
+ */
+
+const literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
+function isLiteral (exp) {
+  return literalValueRE.test(exp)
+}
+
+/**
+ * Strip quotes from a string
+ */
+
+function stripQuotes (str) {
+  const a = str.charCodeAt(0);
+  const b = str.charCodeAt(str.length - 1);
+  return a === b && (a === 0x22 || a === 0x27)
+    ? str.slice(1, -1)
+    : str
+}
+
+/**
+ * Determine the type of a character in a keypath.
+ */
+
+function getPathCharType (ch) {
+  if (ch === undefined || ch === null) { return 'eof' }
+
+  const code = ch.charCodeAt(0);
+
+  switch (code) {
+    case 0x5B: // [
+    case 0x5D: // ]
+    case 0x2E: // .
+    case 0x22: // "
+    case 0x27: // '
+      return ch
+
+    case 0x5F: // _
+    case 0x24: // $
+    case 0x2D: // -
+      return 'ident'
+
+    case 0x09: // Tab
+    case 0x0A: // Newline
+    case 0x0D: // Return
+    case 0xA0:  // No-break space
+    case 0xFEFF:  // Byte Order Mark
+    case 0x2028:  // Line Separator
+    case 0x2029:  // Paragraph Separator
+      return 'ws'
+  }
+
+  return 'ident'
+}
+
+/**
+ * Format a subPath, return its plain form if it is
+ * a literal string or number. Otherwise prepend the
+ * dynamic indicator (*).
+ */
+
+function formatSubPath (path) {
+  const trimmed = path.trim();
+  // invalid leading 0
+  if (path.charAt(0) === '0' && isNaN(path)) { return false }
+
+  return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed
+}
+
+/**
+ * Parse a string path into an array of segments
+ */
+
+function parse$1 (path) {
+  const keys = [];
+  let index = -1;
+  let mode = BEFORE_PATH;
+  let subPathDepth = 0;
+  let c;
+  let key;
+  let newChar;
+  let type;
+  let transition;
+  let action;
+  let typeMap;
+  const actions = [];
+
+  actions[PUSH] = function () {
+    if (key !== undefined) {
+      keys.push(key);
+      key = undefined;
+    }
+  };
+
+  actions[APPEND] = function () {
+    if (key === undefined) {
+      key = newChar;
+    } else {
+      key += newChar;
+    }
+  };
+
+  actions[INC_SUB_PATH_DEPTH] = function () {
+    actions[APPEND]();
+    subPathDepth++;
+  };
+
+  actions[PUSH_SUB_PATH] = function () {
+    if (subPathDepth > 0) {
+      subPathDepth--;
+      mode = IN_SUB_PATH;
+      actions[APPEND]();
+    } else {
+      subPathDepth = 0;
+      if (key === undefined) { return false }
+      key = formatSubPath(key);
+      if (key === false) {
+        return false
+      } else {
+        actions[PUSH]();
+      }
+    }
+  };
+
+  function maybeUnescapeQuote () {
+    const nextChar = path[index + 1];
+    if ((mode === IN_SINGLE_QUOTE && nextChar === "'") ||
+      (mode === IN_DOUBLE_QUOTE && nextChar === '"')) {
+      index++;
+      newChar = '\\' + nextChar;
+      actions[APPEND]();
+      return true
+    }
+  }
+
+  while (mode !== null) {
+    index++;
+    c = path[index];
+
+    if (c === '\\' && maybeUnescapeQuote()) {
+      continue
+    }
+
+    type = getPathCharType(c);
+    typeMap = pathStateMachine[mode];
+    transition = typeMap[type] || typeMap['else'] || ERROR;
+
+    if (transition === ERROR) {
+      return // parse error
+    }
+
+    mode = transition[0];
+    action = actions[transition[1]];
+    if (action) {
+      newChar = transition[2];
+      newChar = newChar === undefined
+        ? c
+        : newChar;
+      if (action() === false) {
+        return
+      }
+    }
+
+    if (mode === AFTER_PATH) {
+      return keys
+    }
+  }
+}
+
+
+
+
+
+class I18nPath {
+  
+
+  constructor () {
+    this._cache = Object.create(null);
+  }
+
+  /**
+   * External parse that check for a cache hit first
+   */
+  parsePath (path) {
+    let hit = this._cache[path];
+    if (!hit) {
+      hit = parse$1(path);
+      if (hit) {
+        this._cache[path] = hit;
+      }
+    }
+    return hit || []
+  }
+
+  /**
+   * Get path value from path string
+   */
+  getPathValue (obj, path) {
+    if (!isObject(obj)) { return null }
+
+    const paths = this.parsePath(path);
+    if (paths.length === 0) {
+      return null
+    } else {
+      const length = paths.length;
+      let last = obj;
+      let i = 0;
+      while (i < length) {
+        const value = last[paths[i]];
+        if (value === undefined) {
+          return null
+        }
+        last = value;
+        i++;
+      }
+
+      return last
+    }
+  }
+}
+
+/*  */
+
+
+
+const htmlTagMatcher = /<\/?[\w\s="/.':;#-\/]+>/;
+const linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
+const linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/;
+const bracketsMatcher = /[()]/g;
+const defaultModifiers = {
+  'upper': str => str.toLocaleUpperCase(),
+  'lower': str => str.toLocaleLowerCase(),
+  'capitalize': str => `${str.charAt(0).toLocaleUpperCase()}${str.substr(1)}`
+};
+
+const defaultFormatter = new BaseFormatter();
+
+class VueI18n {
+  
+  
+  
+
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+
+  constructor (options = {}) {
+    // Auto install if it is not done yet and `window` has `Vue`.
+    // To allow users to avoid auto-installation in some cases,
+    // this code should be placed here. See #290
+    /* istanbul ignore if */
+    if (!Vue && typeof window !== 'undefined' && window.Vue) {
+      install(window.Vue);
+    }
+
+    const locale = options.locale || 'en-US';
+    const fallbackLocale = options.fallbackLocale === false
+      ? false
+      : options.fallbackLocale || 'en-US';
+    const messages = options.messages || {};
+    const dateTimeFormats = options.dateTimeFormats || {};
+    const numberFormats = options.numberFormats || {};
+
+    this._vm = null;
+    this._formatter = options.formatter || defaultFormatter;
+    this._modifiers = options.modifiers || {};
+    this._missing = options.missing || null;
+    this._root = options.root || null;
+    this._sync = options.sync === undefined ? true : !!options.sync;
+    this._fallbackRoot = options.fallbackRoot === undefined
+      ? true
+      : !!options.fallbackRoot;
+    this._formatFallbackMessages = options.formatFallbackMessages === undefined
+      ? false
+      : !!options.formatFallbackMessages;
+    this._silentTranslationWarn = options.silentTranslationWarn === undefined
+      ? false
+      : options.silentTranslationWarn;
+    this._silentFallbackWarn = options.silentFallbackWarn === undefined
+      ? false
+      : !!options.silentFallbackWarn;
+    this._dateTimeFormatters = {};
+    this._numberFormatters = {};
+    this._path = new I18nPath();
+    this._dataListeners = [];
+    this._componentInstanceCreatedListener = options.componentInstanceCreatedListener || null;
+    this._preserveDirectiveContent = options.preserveDirectiveContent === undefined
+      ? false
+      : !!options.preserveDirectiveContent;
+    this.pluralizationRules = options.pluralizationRules || {};
+    this._warnHtmlInMessage = options.warnHtmlInMessage || 'off';
+    this._postTranslation = options.postTranslation || null;
+
+    /**
+     * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
+     * @param choicesLength {number} an overall amount of available choices
+     * @returns a final choice index
+    */
+    this.getChoiceIndex = (choice, choicesLength) => {
+      const thisPrototype = Object.getPrototypeOf(this);
+      if (thisPrototype && thisPrototype.getChoiceIndex) {
+        const prototypeGetChoiceIndex = (thisPrototype.getChoiceIndex);
+        return (prototypeGetChoiceIndex).call(this, choice, choicesLength)
+      }
+
+      // Default (old) getChoiceIndex implementation - english-compatible
+      const defaultImpl = (_choice, _choicesLength) => {
+        _choice = Math.abs(_choice);
+
+        if (_choicesLength === 2) {
+          return _choice
+            ? _choice > 1
+              ? 1
+              : 0
+            : 1
+        }
+
+        return _choice ? Math.min(_choice, 2) : 0
+      };
+
+      if (this.locale in this.pluralizationRules) {
+        return this.pluralizationRules[this.locale].apply(this, [choice, choicesLength])
+      } else {
+        return defaultImpl(choice, choicesLength)
+      }
+    };
+
+
+    this._exist = (message, key) => {
+      if (!message || !key) { return false }
+      if (!isNull(this._path.getPathValue(message, key))) { return true }
+      // fallback for flat key
+      if (message[key]) { return true }
+      return false
+    };
+
+    if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+      Object.keys(messages).forEach(locale => {
+        this._checkLocaleMessage(locale, this._warnHtmlInMessage, messages[locale]);
+      });
+    }
+
+    this._initVM({
+      locale,
+      fallbackLocale,
+      messages,
+      dateTimeFormats,
+      numberFormats
+    });
+  }
+
+  _checkLocaleMessage (locale, level, message) {
+    const paths = [];
+
+    const fn = (level, locale, message, paths) => {
+      if (isPlainObject(message)) {
+        Object.keys(message).forEach(key => {
+          const val = message[key];
+          if (isPlainObject(val)) {
+            paths.push(key);
+            paths.push('.');
+            fn(level, locale, val, paths);
+            paths.pop();
+            paths.pop();
+          } else {
+            paths.push(key);
+            fn(level, locale, val, paths);
+            paths.pop();
+          }
+        });
+      } else if (isArray(message)) {
+        message.forEach((item, index) => {
+          if (isPlainObject(item)) {
+            paths.push(`[${index}]`);
+            paths.push('.');
+            fn(level, locale, item, paths);
+            paths.pop();
+            paths.pop();
+          } else {
+            paths.push(`[${index}]`);
+            fn(level, locale, item, paths);
+            paths.pop();
+          }
+        });
+      } else if (isString(message)) {
+        const ret = htmlTagMatcher.test(message);
+        if (ret) {
+          const msg = `Detected HTML in message '${message}' of keypath '${paths.join('')}' at '${locale}'. Consider component interpolation with '<i18n>' to avoid XSS. See https://bit.ly/2ZqJzkp`;
+          if (level === 'warn') {
+            warn(msg);
+          } else if (level === 'error') {
+            error(msg);
+          }
+        }
+      }
+    };
+
+    fn(level, locale, message, paths);
+  }
+
+  _initVM (data) {
+    const silent = Vue.config.silent;
+    Vue.config.silent = true;
+    this._vm = new Vue({ data });
+    Vue.config.silent = silent;
+  }
+
+  destroyVM () {
+    this._vm.$destroy();
+  }
+
+  subscribeDataChanging (vm) {
+    this._dataListeners.push(vm);
+  }
+
+  unsubscribeDataChanging (vm) {
+    remove(this._dataListeners, vm);
+  }
+
+  watchI18nData () {
+    const self = this;
+    return this._vm.$watch('$data', () => {
+      let i = self._dataListeners.length;
+      while (i--) {
+        Vue.nextTick(() => {
+          self._dataListeners[i] && self._dataListeners[i].$forceUpdate();
+        });
+      }
+    }, { deep: true })
+  }
+
+  watchLocale () {
+    /* istanbul ignore if */
+    if (!this._sync || !this._root) { return null }
+    const target = this._vm;
+    return this._root.$i18n.vm.$watch('locale', (val) => {
+      target.$set(target, 'locale', val);
+      target.$forceUpdate();
+    }, { immediate: true })
+  }
+
+  onComponentInstanceCreated (newI18n) {
+    if (this._componentInstanceCreatedListener) {
+      this._componentInstanceCreatedListener(newI18n, this);
+    }
+  }
+
+  get vm () { return this._vm }
+
+  get messages () { return looseClone(this._getMessages()) }
+  get dateTimeFormats () { return looseClone(this._getDateTimeFormats()) }
+  get numberFormats () { return looseClone(this._getNumberFormats()) }
+  get availableLocales () { return Object.keys(this.messages).sort() }
+
+  get locale () { return this._vm.locale }
+  set locale (locale) {
+    this._vm.$set(this._vm, 'locale', locale);
+  }
+
+  get fallbackLocale () { return this._vm.fallbackLocale }
+  set fallbackLocale (locale) {
+    this._localeChainCache = {};
+    this._vm.$set(this._vm, 'fallbackLocale', locale);
+  }
+
+  get formatFallbackMessages () { return this._formatFallbackMessages }
+  set formatFallbackMessages (fallback) { this._formatFallbackMessages = fallback; }
+
+  get missing () { return this._missing }
+  set missing (handler) { this._missing = handler; }
+
+  get formatter () { return this._formatter }
+  set formatter (formatter) { this._formatter = formatter; }
+
+  get silentTranslationWarn () { return this._silentTranslationWarn }
+  set silentTranslationWarn (silent) { this._silentTranslationWarn = silent; }
+
+  get silentFallbackWarn () { return this._silentFallbackWarn }
+  set silentFallbackWarn (silent) { this._silentFallbackWarn = silent; }
+
+  get preserveDirectiveContent () { return this._preserveDirectiveContent }
+  set preserveDirectiveContent (preserve) { this._preserveDirectiveContent = preserve; }
+
+  get warnHtmlInMessage () { return this._warnHtmlInMessage }
+  set warnHtmlInMessage (level) {
+    const orgLevel = this._warnHtmlInMessage;
+    this._warnHtmlInMessage = level;
+    if (orgLevel !== level && (level === 'warn' || level === 'error')) {
+      const messages = this._getMessages();
+      Object.keys(messages).forEach(locale => {
+        this._checkLocaleMessage(locale, this._warnHtmlInMessage, messages[locale]);
+      });
+    }
+  }
+
+  get postTranslation () { return this._postTranslation }
+  set postTranslation (handler) { this._postTranslation = handler; }
+
+  _getMessages () { return this._vm.messages }
+  _getDateTimeFormats () { return this._vm.dateTimeFormats }
+  _getNumberFormats () { return this._vm.numberFormats }
+
+  _warnDefault (locale, key, result, vm, values, interpolateMode) {
+    if (!isNull(result)) { return result }
+    if (this._missing) {
+      const missingRet = this._missing.apply(null, [locale, key, vm, values]);
+      if (isString(missingRet)) {
+        return missingRet
+      }
+    } else {
+      if (!this._isSilentTranslationWarn(key)) {
+        warn(
+          `Cannot translate the value of keypath '${key}'. ` +
+          'Use the value of keypath as default.'
+        );
+      }
+    }
+
+    if (this._formatFallbackMessages) {
+      const parsedArgs = parseArgs(...values);
+      return this._render(key, interpolateMode, parsedArgs.params, key)
+    } else {
+      return key
+    }
+  }
+
+  _isFallbackRoot (val) {
+    return !val && !isNull(this._root) && this._fallbackRoot
+  }
+
+  _isSilentFallbackWarn (key) {
+    return this._silentFallbackWarn instanceof RegExp
+      ? this._silentFallbackWarn.test(key)
+      : this._silentFallbackWarn
+  }
+
+  _isSilentFallback (locale, key) {
+    return this._isSilentFallbackWarn(key) && (this._isFallbackRoot() || locale !== this.fallbackLocale)
+  }
+
+  _isSilentTranslationWarn (key) {
+    return this._silentTranslationWarn instanceof RegExp
+      ? this._silentTranslationWarn.test(key)
+      : this._silentTranslationWarn
+  }
+
+  _interpolate (
+    locale,
+    message,
+    key,
+    host,
+    interpolateMode,
+    values,
+    visitedLinkStack
+  ) {
+    if (!message) { return null }
+
+    const pathRet = this._path.getPathValue(message, key);
+    if (isArray(pathRet) || isPlainObject(pathRet)) { return pathRet }
+
+    let ret;
+    if (isNull(pathRet)) {
+      /* istanbul ignore else */
+      if (isPlainObject(message)) {
+        ret = message[key];
+        if (!(isString(ret) || isFunction(ret))) {
+          if (!this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+            warn(`Value of key '${key}' is not a string or function !`);
+          }
+          return null
+        }
+      } else {
+        return null
+      }
+    } else {
+      /* istanbul ignore else */
+      if (isString(pathRet) || isFunction(pathRet)) {
+        ret = pathRet;
+      } else {
+        if (!this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+          warn(`Value of key '${key}' is not a string or function!`);
+        }
+        return null
+      }
+    }
+
+    // Check for the existence of links within the translated string
+    if (isString(ret) && (ret.indexOf('@:') >= 0 || ret.indexOf('@.') >= 0)) {
+      ret = this._link(locale, message, ret, host, 'raw', values, visitedLinkStack);
+    }
+
+    return this._render(ret, interpolateMode, values, key)
+  }
+
+  _link (
+    locale,
+    message,
+    str,
+    host,
+    interpolateMode,
+    values,
+    visitedLinkStack
+  ) {
+    let ret = str;
+
+    // Match all the links within the local
+    // We are going to replace each of
+    // them with its translation
+    const matches = ret.match(linkKeyMatcher);
+    for (let idx in matches) {
+      // ie compatible: filter custom array
+      // prototype method
+      if (!matches.hasOwnProperty(idx)) {
+        continue
+      }
+      const link = matches[idx];
+      const linkKeyPrefixMatches = link.match(linkKeyPrefixMatcher);
+      const [linkPrefix, formatterName] = linkKeyPrefixMatches;
+
+      // Remove the leading @:, @.case: and the brackets
+      const linkPlaceholder = link.replace(linkPrefix, '').replace(bracketsMatcher, '');
+
+      if (includes(visitedLinkStack, linkPlaceholder)) {
+        {
+          warn(`Circular reference found. "${link}" is already visited in the chain of ${visitedLinkStack.reverse().join(' <- ')}`);
+        }
+        return ret
+      }
+      visitedLinkStack.push(linkPlaceholder);
+
+      // Translate the link
+      let translated = this._interpolate(
+        locale, message, linkPlaceholder, host,
+        interpolateMode === 'raw' ? 'string' : interpolateMode,
+        interpolateMode === 'raw' ? undefined : values,
+        visitedLinkStack
+      );
+
+      if (this._isFallbackRoot(translated)) {
+        if (!this._isSilentTranslationWarn(linkPlaceholder)) {
+          warn(`Fall back to translate the link placeholder '${linkPlaceholder}' with root locale.`);
+        }
+        /* istanbul ignore if */
+        if (!this._root) { throw Error('unexpected error') }
+        const root = this._root.$i18n;
+        translated = root._translate(
+          root._getMessages(), root.locale, root.fallbackLocale,
+          linkPlaceholder, host, interpolateMode, values
+        );
+      }
+      translated = this._warnDefault(
+        locale, linkPlaceholder, translated, host,
+        isArray(values) ? values : [values],
+        interpolateMode
+      );
+
+      if (this._modifiers.hasOwnProperty(formatterName)) {
+        translated = this._modifiers[formatterName](translated);
+      } else if (defaultModifiers.hasOwnProperty(formatterName)) {
+        translated = defaultModifiers[formatterName](translated);
+      }
+
+      visitedLinkStack.pop();
+
+      // Replace the link with the translated
+      ret = !translated ? ret : ret.replace(link, translated);
+    }
+
+    return ret
+  }
+
+  _createMessageContext (values) {
+    const _list = isArray(values) ? values : [];
+    const _named = isObject(values) ? values : {};
+    const list = (index) => _list[index];
+    const named = (key) => _named[key];
+    return {
+      list,
+      named
+    }
+  }
+
+  _render (message, interpolateMode, values, path) {
+    if (isFunction(message)) {
+      return message(this._createMessageContext(values))
+    }
+
+    let ret = this._formatter.interpolate(message, values, path);
+
+    // If the custom formatter refuses to work - apply the default one
+    if (!ret) {
+      ret = defaultFormatter.interpolate(message, values, path);
+    }
+
+    // if interpolateMode is **not** 'string' ('row'),
+    // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
+    return interpolateMode === 'string' && !isString(ret) ? ret.join('') : ret
+  }
+
+  _appendItemToChain (chain, item, blocks) {
+    let follow = false;
+    if (!includes(chain, item)) {
+      follow = true;
+      if (item) {
+        follow = item[item.length - 1] !== '!';
+        item = item.replace(/!/g, '');
+        chain.push(item);
+        if (blocks && blocks[item]) {
+          follow = blocks[item];
+        }
+      }
+    }
+    return follow
+  }
+
+  _appendLocaleToChain (chain, locale, blocks) {
+    let follow;
+    const tokens = locale.split('-');
+    do {
+      const item = tokens.join('-');
+      follow = this._appendItemToChain(chain, item, blocks);
+      tokens.splice(-1, 1);
+    } while (tokens.length && (follow === true))
+    return follow
+  }
+
+  _appendBlockToChain (chain, block, blocks) {
+    let follow = true;
+    for (let i = 0; (i < block.length) && (isBoolean(follow)); i++) {
+      const locale = block[i];
+      if (isString(locale)) {
+        follow = this._appendLocaleToChain(chain, locale, blocks);
+      }
+    }
+    return follow
+  }
+
+  _getLocaleChain (start, fallbackLocale) {
+    if (start === '') { return [] }
+
+    if (!this._localeChainCache) {
+      this._localeChainCache = {};
+    }
+
+    let chain = this._localeChainCache[start];
+    if (!chain) {
+      if (!fallbackLocale) {
+        fallbackLocale = this.fallbackLocale;
+      }
+      chain = [];
+
+      // first block defined by start
+      let block = [start];
+
+      // while any intervening block found
+      while (isArray(block)) {
+        block = this._appendBlockToChain(
+          chain,
+          block,
+          fallbackLocale
+        );
+      }
+
+      // last block defined by default
+      let defaults;
+      if (isArray(fallbackLocale)) {
+        defaults = fallbackLocale;
+      } else if (isObject(fallbackLocale)) {
+        /* $FlowFixMe */
+        if (fallbackLocale['default']) {
+          defaults = fallbackLocale['default'];
+        } else {
+          defaults = null;
+        }
+      } else {
+        defaults = fallbackLocale;
+      }
+
+      // convert defaults to array
+      if (isString(defaults)) {
+        block = [defaults];
+      } else {
+        block = defaults;
+      }
+      if (block) {
+        this._appendBlockToChain(
+          chain,
+          block,
+          null
+        );
+      }
+      this._localeChainCache[start] = chain;
+    }
+    return chain
+  }
+
+  _translate (
+    messages,
+    locale,
+    fallback,
+    key,
+    host,
+    interpolateMode,
+    args
+  ) {
+    const chain = this._getLocaleChain(locale, fallback);
+    let res;
+    for (let i = 0; i < chain.length; i++) {
+      const step = chain[i];
+      res =
+        this._interpolate(step, messages[step], key, host, interpolateMode, args, [key]);
+      if (!isNull(res)) {
+        if (step !== locale && "development" !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+          warn(("Fall back to translate the keypath '" + key + "' with '" + step + "' locale."));
+        }
+        return res
+      }
+    }
+    return null
+  }
+
+  _t (key, _locale, messages, host, ...values) {
+    if (!key) { return '' }
+
+    const parsedArgs = parseArgs(...values);
+    const locale = parsedArgs.locale || _locale;
+
+    let ret = this._translate(
+      messages, locale, this.fallbackLocale, key,
+      host, 'string', parsedArgs.params
+    );
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(`Fall back to translate the keypath '${key}' with root locale.`);
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$t(key, ...values)
+    } else {
+      ret = this._warnDefault(locale, key, ret, host, values, 'string');
+      if (this._postTranslation && ret !== null && ret !== undefined) {
+        ret = this._postTranslation(ret, key);
+      }
+      return ret
+    }
+  }
+
+  t (key, ...values) {
+    return this._t(key, this.locale, this._getMessages(), null, ...values)
+  }
+
+  _i (key, locale, messages, host, values) {
+    const ret =
+      this._translate(messages, locale, this.fallbackLocale, key, host, 'raw', values);
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key)) {
+        warn(`Fall back to interpolate the keypath '${key}' with root locale.`);
+      }
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n.i(key, locale, values)
+    } else {
+      return this._warnDefault(locale, key, ret, host, [values], 'raw')
+    }
+  }
+
+  i (key, locale, values) {
+    /* istanbul ignore if */
+    if (!key) { return '' }
+
+    if (!isString(locale)) {
+      locale = this.locale;
+    }
+
+    return this._i(key, locale, this._getMessages(), null, values)
+  }
+
+  _tc (
+    key,
+    _locale,
+    messages,
+    host,
+    choice,
+    ...values
+  ) {
+    if (!key) { return '' }
+    if (choice === undefined) {
+      choice = 1;
+    }
+
+    const predefined = { 'count': choice, 'n': choice };
+    const parsedArgs = parseArgs(...values);
+    parsedArgs.params = Object.assign(predefined, parsedArgs.params);
+    values = parsedArgs.locale === null ? [parsedArgs.params] : [parsedArgs.locale, parsedArgs.params];
+    return this.fetchChoice(this._t(key, _locale, messages, host, ...values), choice)
+  }
+
+  fetchChoice (message, choice) {
+    /* istanbul ignore if */
+    if (!message && !isString(message)) { return null }
+    const choices = message.split('|');
+
+    choice = this.getChoiceIndex(choice, choices.length);
+    if (!choices[choice]) { return message }
+    return choices[choice].trim()
+  }
+
+  tc (key, choice, ...values) {
+    return this._tc(key, this.locale, this._getMessages(), null, choice, ...values)
+  }
+
+  _te (key, locale, messages, ...args) {
+    const _locale = parseArgs(...args).locale || locale;
+    return this._exist(messages[_locale], key)
+  }
+
+  te (key, locale) {
+    return this._te(key, this.locale, this._getMessages(), locale)
+  }
+
+  getLocaleMessage (locale) {
+    return looseClone(this._vm.messages[locale] || {})
+  }
+
+  setLocaleMessage (locale, message) {
+    if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+      this._checkLocaleMessage(locale, this._warnHtmlInMessage, message);
+    }
+    this._vm.$set(this._vm.messages, locale, message);
+  }
+
+  mergeLocaleMessage (locale, message) {
+    if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+      this._checkLocaleMessage(locale, this._warnHtmlInMessage, message);
+    }
+    this._vm.$set(this._vm.messages, locale, merge({}, this._vm.messages[locale] || {}, message));
+  }
+
+  getDateTimeFormat (locale) {
+    return looseClone(this._vm.dateTimeFormats[locale] || {})
+  }
+
+  setDateTimeFormat (locale, format) {
+    this._vm.$set(this._vm.dateTimeFormats, locale, format);
+    this._clearDateTimeFormat(locale, format);
+  }
+
+  mergeDateTimeFormat (locale, format) {
+    this._vm.$set(this._vm.dateTimeFormats, locale, merge(this._vm.dateTimeFormats[locale] || {}, format));
+    this._clearDateTimeFormat(locale, format);
+  }
+
+  _clearDateTimeFormat (locale, format) {
+    for (let key in format) {
+      const id = `${locale}__${key}`;
+
+      if (!this._dateTimeFormatters.hasOwnProperty(id)) {
+        continue
+      }
+
+      delete this._dateTimeFormatters[id];
+    }
+  }
+
+  _localizeDateTime (
+    value,
+    locale,
+    fallback,
+    dateTimeFormats,
+    key
+  ) {
+    let _locale = locale;
+    let formats = dateTimeFormats[_locale];
+
+    const chain = this._getLocaleChain(locale, fallback);
+    for (let i = 0; i < chain.length; i++) {
+      const current = _locale;
+      const step = chain[i];
+      formats = dateTimeFormats[step];
+      _locale = step;
+      // fallback locale
+      if (isNull(formats) || isNull(formats[key])) {
+        if (step !== locale && "development" !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+          warn(`Fall back to '${step}' datetime formats from '${current}' datetime formats.`);
+        }
+      } else {
+        break
+      }
+    }
+
+    if (isNull(formats) || isNull(formats[key])) {
+      return null
+    } else {
+      const format = formats[key];
+      const id = `${_locale}__${key}`;
+      let formatter = this._dateTimeFormatters[id];
+      if (!formatter) {
+        formatter = this._dateTimeFormatters[id] = new Intl.DateTimeFormat(_locale, format);
+      }
+      return formatter.format(value)
+    }
+  }
+
+  _d (value, locale, key) {
+    /* istanbul ignore if */
+    if (!VueI18n.availabilities.dateTimeFormat) {
+      warn('Cannot format a Date value due to not supported Intl.DateTimeFormat.');
+      return ''
+    }
+
+    if (!key) {
+      return new Intl.DateTimeFormat(locale).format(value)
+    }
+
+    const ret =
+      this._localizeDateTime(value, locale, this.fallbackLocale, this._getDateTimeFormats(), key);
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(`Fall back to datetime localization of root: key '${key}'.`);
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n.d(value, key, locale)
+    } else {
+      return ret || ''
+    }
+  }
+
+  d (value, ...args) {
+    let locale = this.locale;
+    let key = null;
+
+    if (args.length === 1) {
+      if (isString(args[0])) {
+        key = args[0];
+      } else if (isObject(args[0])) {
+        if (args[0].locale) {
+          locale = args[0].locale;
+        }
+        if (args[0].key) {
+          key = args[0].key;
+        }
+      }
+    } else if (args.length === 2) {
+      if (isString(args[0])) {
+        key = args[0];
+      }
+      if (isString(args[1])) {
+        locale = args[1];
+      }
+    }
+
+    return this._d(value, locale, key)
+  }
+
+  getNumberFormat (locale) {
+    return looseClone(this._vm.numberFormats[locale] || {})
+  }
+
+  setNumberFormat (locale, format) {
+    this._vm.$set(this._vm.numberFormats, locale, format);
+    this._clearNumberFormat(locale, format);
+  }
+
+  mergeNumberFormat (locale, format) {
+    this._vm.$set(this._vm.numberFormats, locale, merge(this._vm.numberFormats[locale] || {}, format));
+    this._clearNumberFormat(locale, format);
+  }
+
+  _clearNumberFormat (locale, format) {
+    for (let key in format) {
+      const id = `${locale}__${key}`;
+
+      if (!this._numberFormatters.hasOwnProperty(id)) {
+        continue
+      }
+
+      delete this._numberFormatters[id];
+    }
+  }
+
+  _getNumberFormatter (
+    value,
+    locale,
+    fallback,
+    numberFormats,
+    key,
+    options
+  ) {
+    let _locale = locale;
+    let formats = numberFormats[_locale];
+
+    const chain = this._getLocaleChain(locale, fallback);
+    for (let i = 0; i < chain.length; i++) {
+      const current = _locale;
+      const step = chain[i];
+      formats = numberFormats[step];
+      _locale = step;
+      // fallback locale
+      if (isNull(formats) || isNull(formats[key])) {
+        if (step !== locale && "development" !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+          warn(`Fall back to '${step}' number formats from '${current}' number formats.`);
+        }
+      } else {
+        break
+      }
+    }
+
+    if (isNull(formats) || isNull(formats[key])) {
+      return null
+    } else {
+      const format = formats[key];
+
+      let formatter;
+      if (options) {
+        // If options specified - create one time number formatter
+        formatter = new Intl.NumberFormat(_locale, Object.assign({}, format, options));
+      } else {
+        const id = `${_locale}__${key}`;
+        formatter = this._numberFormatters[id];
+        if (!formatter) {
+          formatter = this._numberFormatters[id] = new Intl.NumberFormat(_locale, format);
+        }
+      }
+      return formatter
+    }
+  }
+
+  _n (value, locale, key, options) {
+    /* istanbul ignore if */
+    if (!VueI18n.availabilities.numberFormat) {
+      {
+        warn('Cannot format a Number value due to not supported Intl.NumberFormat.');
+      }
+      return ''
+    }
+
+    if (!key) {
+      const nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options);
+      return nf.format(value)
+    }
+
+    const formatter = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
+    const ret = formatter && formatter.format(value);
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(`Fall back to number localization of root: key '${key}'.`);
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n.n(value, Object.assign({}, { key, locale }, options))
+    } else {
+      return ret || ''
+    }
+  }
+
+  n (value, ...args) {
+    let locale = this.locale;
+    let key = null;
+    let options = null;
+
+    if (args.length === 1) {
+      if (isString(args[0])) {
+        key = args[0];
+      } else if (isObject(args[0])) {
+        if (args[0].locale) {
+          locale = args[0].locale;
+        }
+        if (args[0].key) {
+          key = args[0].key;
+        }
+
+        // Filter out number format options only
+        options = Object.keys(args[0]).reduce((acc, key) => {
+          if (includes(numberFormatKeys, key)) {
+            return Object.assign({}, acc, { [key]: args[0][key] })
+          }
+          return acc
+        }, null);
+      }
+    } else if (args.length === 2) {
+      if (isString(args[0])) {
+        key = args[0];
+      }
+      if (isString(args[1])) {
+        locale = args[1];
+      }
+    }
+
+    return this._n(value, locale, key, options)
+  }
+
+  _ntp (value, locale, key, options) {
+    /* istanbul ignore if */
+    if (!VueI18n.availabilities.numberFormat) {
+      {
+        warn('Cannot format to parts a Number value due to not supported Intl.NumberFormat.');
+      }
+      return []
+    }
+
+    if (!key) {
+      const nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options);
+      return nf.formatToParts(value)
+    }
+
+    const formatter = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
+    const ret = formatter && formatter.formatToParts(value);
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key)) {
+        warn(`Fall back to format number to parts of root: key '${key}' .`);
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n._ntp(value, locale, key, options)
+    } else {
+      return ret || []
+    }
+  }
+}
+
+let availabilities;
+// $FlowFixMe
+Object.defineProperty(VueI18n, 'availabilities', {
+  get () {
+    if (!availabilities) {
+      const intlDefined = typeof Intl !== 'undefined';
+      availabilities = {
+        dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
+        numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
+      };
+    }
+
+    return availabilities
+  }
+});
+
+VueI18n.install = install;
+VueI18n.version = '8.21.0';
+
+export default VueI18n;

File diff suppressed because it is too large
+ 0 - 0
plugin/vue-i18n/dist/vue-i18n.esm.browser.min.js


+ 2149 - 0
plugin/vue-i18n/dist/vue-i18n.esm.js

@@ -0,0 +1,2149 @@
+/*!
+ * vue-i18n v8.21.0 
+ * (c) 2020 kazuya kawaguchi
+ * Released under the MIT License.
+ */
+/*  */
+
+/**
+ * constants
+ */
+
+var numberFormatKeys = [
+  'style',
+  'currency',
+  'currencyDisplay',
+  'useGrouping',
+  'minimumIntegerDigits',
+  'minimumFractionDigits',
+  'maximumFractionDigits',
+  'minimumSignificantDigits',
+  'maximumSignificantDigits',
+  'localeMatcher',
+  'formatMatcher',
+  'unit'
+];
+
+/**
+ * utilities
+ */
+
+function warn (msg, err) {
+  if (typeof console !== 'undefined') {
+    console.warn('[vue-i18n] ' + msg);
+    /* istanbul ignore if */
+    if (err) {
+      console.warn(err.stack);
+    }
+  }
+}
+
+function error (msg, err) {
+  if (typeof console !== 'undefined') {
+    console.error('[vue-i18n] ' + msg);
+    /* istanbul ignore if */
+    if (err) {
+      console.error(err.stack);
+    }
+  }
+}
+
+var isArray = Array.isArray;
+
+function isObject (obj) {
+  return obj !== null && typeof obj === 'object'
+}
+
+function isBoolean (val) {
+  return typeof val === 'boolean'
+}
+
+function isString (val) {
+  return typeof val === 'string'
+}
+
+var toString = Object.prototype.toString;
+var OBJECT_STRING = '[object Object]';
+function isPlainObject (obj) {
+  return toString.call(obj) === OBJECT_STRING
+}
+
+function isNull (val) {
+  return val === null || val === undefined
+}
+
+function isFunction (val) {
+  return typeof val === 'function'
+}
+
+function parseArgs () {
+  var args = [], len = arguments.length;
+  while ( len-- ) args[ len ] = arguments[ len ];
+
+  var locale = null;
+  var params = null;
+  if (args.length === 1) {
+    if (isObject(args[0]) || isArray(args[0])) {
+      params = args[0];
+    } else if (typeof args[0] === 'string') {
+      locale = args[0];
+    }
+  } else if (args.length === 2) {
+    if (typeof args[0] === 'string') {
+      locale = args[0];
+    }
+    /* istanbul ignore if */
+    if (isObject(args[1]) || isArray(args[1])) {
+      params = args[1];
+    }
+  }
+
+  return { locale: locale, params: params }
+}
+
+function looseClone (obj) {
+  return JSON.parse(JSON.stringify(obj))
+}
+
+function remove (arr, item) {
+  if (arr.length) {
+    var index = arr.indexOf(item);
+    if (index > -1) {
+      return arr.splice(index, 1)
+    }
+  }
+}
+
+function includes (arr, item) {
+  return !!~arr.indexOf(item)
+}
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+function hasOwn (obj, key) {
+  return hasOwnProperty.call(obj, key)
+}
+
+function merge (target) {
+  var arguments$1 = arguments;
+
+  var output = Object(target);
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments$1[i];
+    if (source !== undefined && source !== null) {
+      var key = (void 0);
+      for (key in source) {
+        if (hasOwn(source, key)) {
+          if (isObject(source[key])) {
+            output[key] = merge(output[key], source[key]);
+          } else {
+            output[key] = source[key];
+          }
+        }
+      }
+    }
+  }
+  return output
+}
+
+function looseEqual (a, b) {
+  if (a === b) { return true }
+  var isObjectA = isObject(a);
+  var isObjectB = isObject(b);
+  if (isObjectA && isObjectB) {
+    try {
+      var isArrayA = isArray(a);
+      var isArrayB = isArray(b);
+      if (isArrayA && isArrayB) {
+        return a.length === b.length && a.every(function (e, i) {
+          return looseEqual(e, b[i])
+        })
+      } else if (!isArrayA && !isArrayB) {
+        var keysA = Object.keys(a);
+        var keysB = Object.keys(b);
+        return keysA.length === keysB.length && keysA.every(function (key) {
+          return looseEqual(a[key], b[key])
+        })
+      } else {
+        /* istanbul ignore next */
+        return false
+      }
+    } catch (e) {
+      /* istanbul ignore next */
+      return false
+    }
+  } else if (!isObjectA && !isObjectB) {
+    return String(a) === String(b)
+  } else {
+    return false
+  }
+}
+
+/*  */
+
+function extend (Vue) {
+  if (!Vue.prototype.hasOwnProperty('$i18n')) {
+    // $FlowFixMe
+    Object.defineProperty(Vue.prototype, '$i18n', {
+      get: function get () { return this._i18n }
+    });
+  }
+
+  Vue.prototype.$t = function (key) {
+    var values = [], len = arguments.length - 1;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 1 ];
+
+    var i18n = this.$i18n;
+    return i18n._t.apply(i18n, [ key, i18n.locale, i18n._getMessages(), this ].concat( values ))
+  };
+
+  Vue.prototype.$tc = function (key, choice) {
+    var values = [], len = arguments.length - 2;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 2 ];
+
+    var i18n = this.$i18n;
+    return i18n._tc.apply(i18n, [ key, i18n.locale, i18n._getMessages(), this, choice ].concat( values ))
+  };
+
+  Vue.prototype.$te = function (key, locale) {
+    var i18n = this.$i18n;
+    return i18n._te(key, i18n.locale, i18n._getMessages(), locale)
+  };
+
+  Vue.prototype.$d = function (value) {
+    var ref;
+
+    var args = [], len = arguments.length - 1;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+    return (ref = this.$i18n).d.apply(ref, [ value ].concat( args ))
+  };
+
+  Vue.prototype.$n = function (value) {
+    var ref;
+
+    var args = [], len = arguments.length - 1;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+    return (ref = this.$i18n).n.apply(ref, [ value ].concat( args ))
+  };
+}
+
+/*  */
+
+var mixin = {
+  beforeCreate: function beforeCreate () {
+    var options = this.$options;
+    options.i18n = options.i18n || (options.__i18n ? {} : null);
+
+    if (options.i18n) {
+      if (options.i18n instanceof VueI18n) {
+        // init locale messages via custom blocks
+        if (options.__i18n) {
+          try {
+            var localeMessages = {};
+            options.__i18n.forEach(function (resource) {
+              localeMessages = merge(localeMessages, JSON.parse(resource));
+            });
+            Object.keys(localeMessages).forEach(function (locale) {
+              options.i18n.mergeLocaleMessage(locale, localeMessages[locale]);
+            });
+          } catch (e) {
+            if (process.env.NODE_ENV !== 'production') {
+              error("Cannot parse locale messages via custom blocks.", e);
+            }
+          }
+        }
+        this._i18n = options.i18n;
+        this._i18nWatcher = this._i18n.watchI18nData();
+      } else if (isPlainObject(options.i18n)) {
+        var rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
+          ? this.$root.$i18n
+          : null;
+        // component local i18n
+        if (rootI18n) {
+          options.i18n.root = this.$root;
+          options.i18n.formatter = rootI18n.formatter;
+          options.i18n.fallbackLocale = rootI18n.fallbackLocale;
+          options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages;
+          options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn;
+          options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn;
+          options.i18n.pluralizationRules = rootI18n.pluralizationRules;
+          options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent;
+        }
+
+        // init locale messages via custom blocks
+        if (options.__i18n) {
+          try {
+            var localeMessages$1 = {};
+            options.__i18n.forEach(function (resource) {
+              localeMessages$1 = merge(localeMessages$1, JSON.parse(resource));
+            });
+            options.i18n.messages = localeMessages$1;
+          } catch (e) {
+            if (process.env.NODE_ENV !== 'production') {
+              warn("Cannot parse locale messages via custom blocks.", e);
+            }
+          }
+        }
+
+        var ref = options.i18n;
+        var sharedMessages = ref.sharedMessages;
+        if (sharedMessages && isPlainObject(sharedMessages)) {
+          options.i18n.messages = merge(options.i18n.messages, sharedMessages);
+        }
+
+        this._i18n = new VueI18n(options.i18n);
+        this._i18nWatcher = this._i18n.watchI18nData();
+
+        if (options.i18n.sync === undefined || !!options.i18n.sync) {
+          this._localeWatcher = this.$i18n.watchLocale();
+        }
+
+        if (rootI18n) {
+          rootI18n.onComponentInstanceCreated(this._i18n);
+        }
+      } else {
+        if (process.env.NODE_ENV !== 'production') {
+          warn("Cannot be interpreted 'i18n' option.");
+        }
+      }
+    } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+      // root i18n
+      this._i18n = this.$root.$i18n;
+    } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+      // parent i18n
+      this._i18n = options.parent.$i18n;
+    }
+  },
+
+  beforeMount: function beforeMount () {
+    var options = this.$options;
+    options.i18n = options.i18n || (options.__i18n ? {} : null);
+
+    if (options.i18n) {
+      if (options.i18n instanceof VueI18n) {
+        // init locale messages via custom blocks
+        this._i18n.subscribeDataChanging(this);
+        this._subscribing = true;
+      } else if (isPlainObject(options.i18n)) {
+        this._i18n.subscribeDataChanging(this);
+        this._subscribing = true;
+      } else {
+        if (process.env.NODE_ENV !== 'production') {
+          warn("Cannot be interpreted 'i18n' option.");
+        }
+      }
+    } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+      this._i18n.subscribeDataChanging(this);
+      this._subscribing = true;
+    } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+      this._i18n.subscribeDataChanging(this);
+      this._subscribing = true;
+    }
+  },
+
+  beforeDestroy: function beforeDestroy () {
+    if (!this._i18n) { return }
+
+    var self = this;
+    this.$nextTick(function () {
+      if (self._subscribing) {
+        self._i18n.unsubscribeDataChanging(self);
+        delete self._subscribing;
+      }
+
+      if (self._i18nWatcher) {
+        self._i18nWatcher();
+        self._i18n.destroyVM();
+        delete self._i18nWatcher;
+      }
+
+      if (self._localeWatcher) {
+        self._localeWatcher();
+        delete self._localeWatcher;
+      }
+    });
+  }
+};
+
+/*  */
+
+var interpolationComponent = {
+  name: 'i18n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    path: {
+      type: String,
+      required: true
+    },
+    locale: {
+      type: String
+    },
+    places: {
+      type: [Array, Object]
+    }
+  },
+  render: function render (h, ref) {
+    var data = ref.data;
+    var parent = ref.parent;
+    var props = ref.props;
+    var slots = ref.slots;
+
+    var $i18n = parent.$i18n;
+    if (!$i18n) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot find VueI18n instance!');
+      }
+      return
+    }
+
+    var path = props.path;
+    var locale = props.locale;
+    var places = props.places;
+    var params = slots();
+    var children = $i18n.i(
+      path,
+      locale,
+      onlyHasDefaultPlace(params) || places
+        ? useLegacyPlaces(params.default, places)
+        : params
+    );
+
+    var tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span';
+    return tag ? h(tag, data, children) : children
+  }
+};
+
+function onlyHasDefaultPlace (params) {
+  var prop;
+  for (prop in params) {
+    if (prop !== 'default') { return false }
+  }
+  return Boolean(prop)
+}
+
+function useLegacyPlaces (children, places) {
+  var params = places ? createParamsFromPlaces(places) : {};
+
+  if (!children) { return params }
+
+  // Filter empty text nodes
+  children = children.filter(function (child) {
+    return child.tag || child.text.trim() !== ''
+  });
+
+  var everyPlace = children.every(vnodeHasPlaceAttribute);
+  if (process.env.NODE_ENV !== 'production' && everyPlace) {
+    warn('`place` attribute is deprecated in next major version. Please switch to Vue slots.');
+  }
+
+  return children.reduce(
+    everyPlace ? assignChildPlace : assignChildIndex,
+    params
+  )
+}
+
+function createParamsFromPlaces (places) {
+  if (process.env.NODE_ENV !== 'production') {
+    warn('`places` prop is deprecated in next major version. Please switch to Vue slots.');
+  }
+
+  return Array.isArray(places)
+    ? places.reduce(assignChildIndex, {})
+    : Object.assign({}, places)
+}
+
+function assignChildPlace (params, child) {
+  if (child.data && child.data.attrs && child.data.attrs.place) {
+    params[child.data.attrs.place] = child;
+  }
+  return params
+}
+
+function assignChildIndex (params, child, index) {
+  params[index] = child;
+  return params
+}
+
+function vnodeHasPlaceAttribute (vnode) {
+  return Boolean(vnode.data && vnode.data.attrs && vnode.data.attrs.place)
+}
+
+/*  */
+
+var numberComponent = {
+  name: 'i18n-n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    value: {
+      type: Number,
+      required: true
+    },
+    format: {
+      type: [String, Object]
+    },
+    locale: {
+      type: String
+    }
+  },
+  render: function render (h, ref) {
+    var props = ref.props;
+    var parent = ref.parent;
+    var data = ref.data;
+
+    var i18n = parent.$i18n;
+
+    if (!i18n) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot find VueI18n instance!');
+      }
+      return null
+    }
+
+    var key = null;
+    var options = null;
+
+    if (isString(props.format)) {
+      key = props.format;
+    } else if (isObject(props.format)) {
+      if (props.format.key) {
+        key = props.format.key;
+      }
+
+      // Filter out number format options only
+      options = Object.keys(props.format).reduce(function (acc, prop) {
+        var obj;
+
+        if (includes(numberFormatKeys, prop)) {
+          return Object.assign({}, acc, ( obj = {}, obj[prop] = props.format[prop], obj ))
+        }
+        return acc
+      }, null);
+    }
+
+    var locale = props.locale || i18n.locale;
+    var parts = i18n._ntp(props.value, locale, key, options);
+
+    var values = parts.map(function (part, index) {
+      var obj;
+
+      var slot = data.scopedSlots && data.scopedSlots[part.type];
+      return slot ? slot(( obj = {}, obj[part.type] = part.value, obj.index = index, obj.parts = parts, obj )) : part.value
+    });
+
+    var tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span';
+    return tag
+      ? h(tag, {
+        attrs: data.attrs,
+        'class': data['class'],
+        staticClass: data.staticClass
+      }, values)
+      : values
+  }
+};
+
+/*  */
+
+function bind (el, binding, vnode) {
+  if (!assert(el, vnode)) { return }
+
+  t(el, binding, vnode);
+}
+
+function update (el, binding, vnode, oldVNode) {
+  if (!assert(el, vnode)) { return }
+
+  var i18n = vnode.context.$i18n;
+  if (localeEqual(el, vnode) &&
+    (looseEqual(binding.value, binding.oldValue) &&
+     looseEqual(el._localeMessage, i18n.getLocaleMessage(i18n.locale)))) { return }
+
+  t(el, binding, vnode);
+}
+
+function unbind (el, binding, vnode, oldVNode) {
+  var vm = vnode.context;
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context');
+    return
+  }
+
+  var i18n = vnode.context.$i18n || {};
+  if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
+    el.textContent = '';
+  }
+  el._vt = undefined;
+  delete el['_vt'];
+  el._locale = undefined;
+  delete el['_locale'];
+  el._localeMessage = undefined;
+  delete el['_localeMessage'];
+}
+
+function assert (el, vnode) {
+  var vm = vnode.context;
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context');
+    return false
+  }
+
+  if (!vm.$i18n) {
+    warn('VueI18n instance does not exists in Vue instance');
+    return false
+  }
+
+  return true
+}
+
+function localeEqual (el, vnode) {
+  var vm = vnode.context;
+  return el._locale === vm.$i18n.locale
+}
+
+function t (el, binding, vnode) {
+  var ref$1, ref$2;
+
+  var value = binding.value;
+
+  var ref = parseValue(value);
+  var path = ref.path;
+  var locale = ref.locale;
+  var args = ref.args;
+  var choice = ref.choice;
+  if (!path && !locale && !args) {
+    warn('value type not supported');
+    return
+  }
+
+  if (!path) {
+    warn('`path` is required in v-t directive');
+    return
+  }
+
+  var vm = vnode.context;
+  if (choice != null) {
+    el._vt = el.textContent = (ref$1 = vm.$i18n).tc.apply(ref$1, [ path, choice ].concat( makeParams(locale, args) ));
+  } else {
+    el._vt = el.textContent = (ref$2 = vm.$i18n).t.apply(ref$2, [ path ].concat( makeParams(locale, args) ));
+  }
+  el._locale = vm.$i18n.locale;
+  el._localeMessage = vm.$i18n.getLocaleMessage(vm.$i18n.locale);
+}
+
+function parseValue (value) {
+  var path;
+  var locale;
+  var args;
+  var choice;
+
+  if (isString(value)) {
+    path = value;
+  } else if (isPlainObject(value)) {
+    path = value.path;
+    locale = value.locale;
+    args = value.args;
+    choice = value.choice;
+  }
+
+  return { path: path, locale: locale, args: args, choice: choice }
+}
+
+function makeParams (locale, args) {
+  var params = [];
+
+  locale && params.push(locale);
+  if (args && (Array.isArray(args) || isPlainObject(args))) {
+    params.push(args);
+  }
+
+  return params
+}
+
+var Vue;
+
+function install (_Vue) {
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && install.installed && _Vue === Vue) {
+    warn('already installed.');
+    return
+  }
+  install.installed = true;
+
+  Vue = _Vue;
+
+  var version = (Vue.version && Number(Vue.version.split('.')[0])) || -1;
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && version < 2) {
+    warn(("vue-i18n (" + (install.version) + ") need to use Vue 2.0 or later (Vue: " + (Vue.version) + ")."));
+    return
+  }
+
+  extend(Vue);
+  Vue.mixin(mixin);
+  Vue.directive('t', { bind: bind, update: update, unbind: unbind });
+  Vue.component(interpolationComponent.name, interpolationComponent);
+  Vue.component(numberComponent.name, numberComponent);
+
+  // use simple mergeStrategies to prevent i18n instance lose '__proto__'
+  var strats = Vue.config.optionMergeStrategies;
+  strats.i18n = function (parentVal, childVal) {
+    return childVal === undefined
+      ? parentVal
+      : childVal
+  };
+}
+
+/*  */
+
+var BaseFormatter = function BaseFormatter () {
+  this._caches = Object.create(null);
+};
+
+BaseFormatter.prototype.interpolate = function interpolate (message, values) {
+  if (!values) {
+    return [message]
+  }
+  var tokens = this._caches[message];
+  if (!tokens) {
+    tokens = parse(message);
+    this._caches[message] = tokens;
+  }
+  return compile(tokens, values)
+};
+
+
+
+var RE_TOKEN_LIST_VALUE = /^(?:\d)+/;
+var RE_TOKEN_NAMED_VALUE = /^(?:\w)+/;
+
+function parse (format) {
+  var tokens = [];
+  var position = 0;
+
+  var text = '';
+  while (position < format.length) {
+    var char = format[position++];
+    if (char === '{') {
+      if (text) {
+        tokens.push({ type: 'text', value: text });
+      }
+
+      text = '';
+      var sub = '';
+      char = format[position++];
+      while (char !== undefined && char !== '}') {
+        sub += char;
+        char = format[position++];
+      }
+      var isClosed = char === '}';
+
+      var type = RE_TOKEN_LIST_VALUE.test(sub)
+        ? 'list'
+        : isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
+          ? 'named'
+          : 'unknown';
+      tokens.push({ value: sub, type: type });
+    } else if (char === '%') {
+      // when found rails i18n syntax, skip text capture
+      if (format[(position)] !== '{') {
+        text += char;
+      }
+    } else {
+      text += char;
+    }
+  }
+
+  text && tokens.push({ type: 'text', value: text });
+
+  return tokens
+}
+
+function compile (tokens, values) {
+  var compiled = [];
+  var index = 0;
+
+  var mode = Array.isArray(values)
+    ? 'list'
+    : isObject(values)
+      ? 'named'
+      : 'unknown';
+  if (mode === 'unknown') { return compiled }
+
+  while (index < tokens.length) {
+    var token = tokens[index];
+    switch (token.type) {
+      case 'text':
+        compiled.push(token.value);
+        break
+      case 'list':
+        compiled.push(values[parseInt(token.value, 10)]);
+        break
+      case 'named':
+        if (mode === 'named') {
+          compiled.push((values)[token.value]);
+        } else {
+          if (process.env.NODE_ENV !== 'production') {
+            warn(("Type of token '" + (token.type) + "' and format of value '" + mode + "' don't match!"));
+          }
+        }
+        break
+      case 'unknown':
+        if (process.env.NODE_ENV !== 'production') {
+          warn("Detect 'unknown' type of token!");
+        }
+        break
+    }
+    index++;
+  }
+
+  return compiled
+}
+
+/*  */
+
+/**
+ *  Path parser
+ *  - Inspired:
+ *    Vue.js Path parser
+ */
+
+// actions
+var APPEND = 0;
+var PUSH = 1;
+var INC_SUB_PATH_DEPTH = 2;
+var PUSH_SUB_PATH = 3;
+
+// states
+var BEFORE_PATH = 0;
+var IN_PATH = 1;
+var BEFORE_IDENT = 2;
+var IN_IDENT = 3;
+var IN_SUB_PATH = 4;
+var IN_SINGLE_QUOTE = 5;
+var IN_DOUBLE_QUOTE = 6;
+var AFTER_PATH = 7;
+var ERROR = 8;
+
+var pathStateMachine = [];
+
+pathStateMachine[BEFORE_PATH] = {
+  'ws': [BEFORE_PATH],
+  'ident': [IN_IDENT, APPEND],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+};
+
+pathStateMachine[IN_PATH] = {
+  'ws': [IN_PATH],
+  '.': [BEFORE_IDENT],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+};
+
+pathStateMachine[BEFORE_IDENT] = {
+  'ws': [BEFORE_IDENT],
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND]
+};
+
+pathStateMachine[IN_IDENT] = {
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND],
+  'ws': [IN_PATH, PUSH],
+  '.': [BEFORE_IDENT, PUSH],
+  '[': [IN_SUB_PATH, PUSH],
+  'eof': [AFTER_PATH, PUSH]
+};
+
+pathStateMachine[IN_SUB_PATH] = {
+  "'": [IN_SINGLE_QUOTE, APPEND],
+  '"': [IN_DOUBLE_QUOTE, APPEND],
+  '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
+  ']': [IN_PATH, PUSH_SUB_PATH],
+  'eof': ERROR,
+  'else': [IN_SUB_PATH, APPEND]
+};
+
+pathStateMachine[IN_SINGLE_QUOTE] = {
+  "'": [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_SINGLE_QUOTE, APPEND]
+};
+
+pathStateMachine[IN_DOUBLE_QUOTE] = {
+  '"': [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_DOUBLE_QUOTE, APPEND]
+};
+
+/**
+ * Check if an expression is a literal value.
+ */
+
+var literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
+function isLiteral (exp) {
+  return literalValueRE.test(exp)
+}
+
+/**
+ * Strip quotes from a string
+ */
+
+function stripQuotes (str) {
+  var a = str.charCodeAt(0);
+  var b = str.charCodeAt(str.length - 1);
+  return a === b && (a === 0x22 || a === 0x27)
+    ? str.slice(1, -1)
+    : str
+}
+
+/**
+ * Determine the type of a character in a keypath.
+ */
+
+function getPathCharType (ch) {
+  if (ch === undefined || ch === null) { return 'eof' }
+
+  var code = ch.charCodeAt(0);
+
+  switch (code) {
+    case 0x5B: // [
+    case 0x5D: // ]
+    case 0x2E: // .
+    case 0x22: // "
+    case 0x27: // '
+      return ch
+
+    case 0x5F: // _
+    case 0x24: // $
+    case 0x2D: // -
+      return 'ident'
+
+    case 0x09: // Tab
+    case 0x0A: // Newline
+    case 0x0D: // Return
+    case 0xA0:  // No-break space
+    case 0xFEFF:  // Byte Order Mark
+    case 0x2028:  // Line Separator
+    case 0x2029:  // Paragraph Separator
+      return 'ws'
+  }
+
+  return 'ident'
+}
+
+/**
+ * Format a subPath, return its plain form if it is
+ * a literal string or number. Otherwise prepend the
+ * dynamic indicator (*).
+ */
+
+function formatSubPath (path) {
+  var trimmed = path.trim();
+  // invalid leading 0
+  if (path.charAt(0) === '0' && isNaN(path)) { return false }
+
+  return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed
+}
+
+/**
+ * Parse a string path into an array of segments
+ */
+
+function parse$1 (path) {
+  var keys = [];
+  var index = -1;
+  var mode = BEFORE_PATH;
+  var subPathDepth = 0;
+  var c;
+  var key;
+  var newChar;
+  var type;
+  var transition;
+  var action;
+  var typeMap;
+  var actions = [];
+
+  actions[PUSH] = function () {
+    if (key !== undefined) {
+      keys.push(key);
+      key = undefined;
+    }
+  };
+
+  actions[APPEND] = function () {
+    if (key === undefined) {
+      key = newChar;
+    } else {
+      key += newChar;
+    }
+  };
+
+  actions[INC_SUB_PATH_DEPTH] = function () {
+    actions[APPEND]();
+    subPathDepth++;
+  };
+
+  actions[PUSH_SUB_PATH] = function () {
+    if (subPathDepth > 0) {
+      subPathDepth--;
+      mode = IN_SUB_PATH;
+      actions[APPEND]();
+    } else {
+      subPathDepth = 0;
+      if (key === undefined) { return false }
+      key = formatSubPath(key);
+      if (key === false) {
+        return false
+      } else {
+        actions[PUSH]();
+      }
+    }
+  };
+
+  function maybeUnescapeQuote () {
+    var nextChar = path[index + 1];
+    if ((mode === IN_SINGLE_QUOTE && nextChar === "'") ||
+      (mode === IN_DOUBLE_QUOTE && nextChar === '"')) {
+      index++;
+      newChar = '\\' + nextChar;
+      actions[APPEND]();
+      return true
+    }
+  }
+
+  while (mode !== null) {
+    index++;
+    c = path[index];
+
+    if (c === '\\' && maybeUnescapeQuote()) {
+      continue
+    }
+
+    type = getPathCharType(c);
+    typeMap = pathStateMachine[mode];
+    transition = typeMap[type] || typeMap['else'] || ERROR;
+
+    if (transition === ERROR) {
+      return // parse error
+    }
+
+    mode = transition[0];
+    action = actions[transition[1]];
+    if (action) {
+      newChar = transition[2];
+      newChar = newChar === undefined
+        ? c
+        : newChar;
+      if (action() === false) {
+        return
+      }
+    }
+
+    if (mode === AFTER_PATH) {
+      return keys
+    }
+  }
+}
+
+
+
+
+
+var I18nPath = function I18nPath () {
+  this._cache = Object.create(null);
+};
+
+/**
+ * External parse that check for a cache hit first
+ */
+I18nPath.prototype.parsePath = function parsePath (path) {
+  var hit = this._cache[path];
+  if (!hit) {
+    hit = parse$1(path);
+    if (hit) {
+      this._cache[path] = hit;
+    }
+  }
+  return hit || []
+};
+
+/**
+ * Get path value from path string
+ */
+I18nPath.prototype.getPathValue = function getPathValue (obj, path) {
+  if (!isObject(obj)) { return null }
+
+  var paths = this.parsePath(path);
+  if (paths.length === 0) {
+    return null
+  } else {
+    var length = paths.length;
+    var last = obj;
+    var i = 0;
+    while (i < length) {
+      var value = last[paths[i]];
+      if (value === undefined) {
+        return null
+      }
+      last = value;
+      i++;
+    }
+
+    return last
+  }
+};
+
+/*  */
+
+
+
+var htmlTagMatcher = /<\/?[\w\s="/.':;#-\/]+>/;
+var linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
+var linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/;
+var bracketsMatcher = /[()]/g;
+var defaultModifiers = {
+  'upper': function (str) { return str.toLocaleUpperCase(); },
+  'lower': function (str) { return str.toLocaleLowerCase(); },
+  'capitalize': function (str) { return ("" + (str.charAt(0).toLocaleUpperCase()) + (str.substr(1))); }
+};
+
+var defaultFormatter = new BaseFormatter();
+
+var VueI18n = function VueI18n (options) {
+  var this$1 = this;
+  if ( options === void 0 ) options = {};
+
+  // Auto install if it is not done yet and `window` has `Vue`.
+  // To allow users to avoid auto-installation in some cases,
+  // this code should be placed here. See #290
+  /* istanbul ignore if */
+  if (!Vue && typeof window !== 'undefined' && window.Vue) {
+    install(window.Vue);
+  }
+
+  var locale = options.locale || 'en-US';
+  var fallbackLocale = options.fallbackLocale === false
+    ? false
+    : options.fallbackLocale || 'en-US';
+  var messages = options.messages || {};
+  var dateTimeFormats = options.dateTimeFormats || {};
+  var numberFormats = options.numberFormats || {};
+
+  this._vm = null;
+  this._formatter = options.formatter || defaultFormatter;
+  this._modifiers = options.modifiers || {};
+  this._missing = options.missing || null;
+  this._root = options.root || null;
+  this._sync = options.sync === undefined ? true : !!options.sync;
+  this._fallbackRoot = options.fallbackRoot === undefined
+    ? true
+    : !!options.fallbackRoot;
+  this._formatFallbackMessages = options.formatFallbackMessages === undefined
+    ? false
+    : !!options.formatFallbackMessages;
+  this._silentTranslationWarn = options.silentTranslationWarn === undefined
+    ? false
+    : options.silentTranslationWarn;
+  this._silentFallbackWarn = options.silentFallbackWarn === undefined
+    ? false
+    : !!options.silentFallbackWarn;
+  this._dateTimeFormatters = {};
+  this._numberFormatters = {};
+  this._path = new I18nPath();
+  this._dataListeners = [];
+  this._componentInstanceCreatedListener = options.componentInstanceCreatedListener || null;
+  this._preserveDirectiveContent = options.preserveDirectiveContent === undefined
+    ? false
+    : !!options.preserveDirectiveContent;
+  this.pluralizationRules = options.pluralizationRules || {};
+  this._warnHtmlInMessage = options.warnHtmlInMessage || 'off';
+  this._postTranslation = options.postTranslation || null;
+
+  /**
+   * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
+   * @param choicesLength {number} an overall amount of available choices
+   * @returns a final choice index
+  */
+  this.getChoiceIndex = function (choice, choicesLength) {
+    var thisPrototype = Object.getPrototypeOf(this$1);
+    if (thisPrototype && thisPrototype.getChoiceIndex) {
+      var prototypeGetChoiceIndex = (thisPrototype.getChoiceIndex);
+      return (prototypeGetChoiceIndex).call(this$1, choice, choicesLength)
+    }
+
+    // Default (old) getChoiceIndex implementation - english-compatible
+    var defaultImpl = function (_choice, _choicesLength) {
+      _choice = Math.abs(_choice);
+
+      if (_choicesLength === 2) {
+        return _choice
+          ? _choice > 1
+            ? 1
+            : 0
+          : 1
+      }
+
+      return _choice ? Math.min(_choice, 2) : 0
+    };
+
+    if (this$1.locale in this$1.pluralizationRules) {
+      return this$1.pluralizationRules[this$1.locale].apply(this$1, [choice, choicesLength])
+    } else {
+      return defaultImpl(choice, choicesLength)
+    }
+  };
+
+
+  this._exist = function (message, key) {
+    if (!message || !key) { return false }
+    if (!isNull(this$1._path.getPathValue(message, key))) { return true }
+    // fallback for flat key
+    if (message[key]) { return true }
+    return false
+  };
+
+  if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+    Object.keys(messages).forEach(function (locale) {
+      this$1._checkLocaleMessage(locale, this$1._warnHtmlInMessage, messages[locale]);
+    });
+  }
+
+  this._initVM({
+    locale: locale,
+    fallbackLocale: fallbackLocale,
+    messages: messages,
+    dateTimeFormats: dateTimeFormats,
+    numberFormats: numberFormats
+  });
+};
+
+var prototypeAccessors = { vm: { configurable: true },messages: { configurable: true },dateTimeFormats: { configurable: true },numberFormats: { configurable: true },availableLocales: { configurable: true },locale: { configurable: true },fallbackLocale: { configurable: true },formatFallbackMessages: { configurable: true },missing: { configurable: true },formatter: { configurable: true },silentTranslationWarn: { configurable: true },silentFallbackWarn: { configurable: true },preserveDirectiveContent: { configurable: true },warnHtmlInMessage: { configurable: true },postTranslation: { configurable: true } };
+
+VueI18n.prototype._checkLocaleMessage = function _checkLocaleMessage (locale, level, message) {
+  var paths = [];
+
+  var fn = function (level, locale, message, paths) {
+    if (isPlainObject(message)) {
+      Object.keys(message).forEach(function (key) {
+        var val = message[key];
+        if (isPlainObject(val)) {
+          paths.push(key);
+          paths.push('.');
+          fn(level, locale, val, paths);
+          paths.pop();
+          paths.pop();
+        } else {
+          paths.push(key);
+          fn(level, locale, val, paths);
+          paths.pop();
+        }
+      });
+    } else if (isArray(message)) {
+      message.forEach(function (item, index) {
+        if (isPlainObject(item)) {
+          paths.push(("[" + index + "]"));
+          paths.push('.');
+          fn(level, locale, item, paths);
+          paths.pop();
+          paths.pop();
+        } else {
+          paths.push(("[" + index + "]"));
+          fn(level, locale, item, paths);
+          paths.pop();
+        }
+      });
+    } else if (isString(message)) {
+      var ret = htmlTagMatcher.test(message);
+      if (ret) {
+        var msg = "Detected HTML in message '" + message + "' of keypath '" + (paths.join('')) + "' at '" + locale + "'. Consider component interpolation with '<i18n>' to avoid XSS. See https://bit.ly/2ZqJzkp";
+        if (level === 'warn') {
+          warn(msg);
+        } else if (level === 'error') {
+          error(msg);
+        }
+      }
+    }
+  };
+
+  fn(level, locale, message, paths);
+};
+
+VueI18n.prototype._initVM = function _initVM (data) {
+  var silent = Vue.config.silent;
+  Vue.config.silent = true;
+  this._vm = new Vue({ data: data });
+  Vue.config.silent = silent;
+};
+
+VueI18n.prototype.destroyVM = function destroyVM () {
+  this._vm.$destroy();
+};
+
+VueI18n.prototype.subscribeDataChanging = function subscribeDataChanging (vm) {
+  this._dataListeners.push(vm);
+};
+
+VueI18n.prototype.unsubscribeDataChanging = function unsubscribeDataChanging (vm) {
+  remove(this._dataListeners, vm);
+};
+
+VueI18n.prototype.watchI18nData = function watchI18nData () {
+  var self = this;
+  return this._vm.$watch('$data', function () {
+    var i = self._dataListeners.length;
+    while (i--) {
+      Vue.nextTick(function () {
+        self._dataListeners[i] && self._dataListeners[i].$forceUpdate();
+      });
+    }
+  }, { deep: true })
+};
+
+VueI18n.prototype.watchLocale = function watchLocale () {
+  /* istanbul ignore if */
+  if (!this._sync || !this._root) { return null }
+  var target = this._vm;
+  return this._root.$i18n.vm.$watch('locale', function (val) {
+    target.$set(target, 'locale', val);
+    target.$forceUpdate();
+  }, { immediate: true })
+};
+
+VueI18n.prototype.onComponentInstanceCreated = function onComponentInstanceCreated (newI18n) {
+  if (this._componentInstanceCreatedListener) {
+    this._componentInstanceCreatedListener(newI18n, this);
+  }
+};
+
+prototypeAccessors.vm.get = function () { return this._vm };
+
+prototypeAccessors.messages.get = function () { return looseClone(this._getMessages()) };
+prototypeAccessors.dateTimeFormats.get = function () { return looseClone(this._getDateTimeFormats()) };
+prototypeAccessors.numberFormats.get = function () { return looseClone(this._getNumberFormats()) };
+prototypeAccessors.availableLocales.get = function () { return Object.keys(this.messages).sort() };
+
+prototypeAccessors.locale.get = function () { return this._vm.locale };
+prototypeAccessors.locale.set = function (locale) {
+  this._vm.$set(this._vm, 'locale', locale);
+};
+
+prototypeAccessors.fallbackLocale.get = function () { return this._vm.fallbackLocale };
+prototypeAccessors.fallbackLocale.set = function (locale) {
+  this._localeChainCache = {};
+  this._vm.$set(this._vm, 'fallbackLocale', locale);
+};
+
+prototypeAccessors.formatFallbackMessages.get = function () { return this._formatFallbackMessages };
+prototypeAccessors.formatFallbackMessages.set = function (fallback) { this._formatFallbackMessages = fallback; };
+
+prototypeAccessors.missing.get = function () { return this._missing };
+prototypeAccessors.missing.set = function (handler) { this._missing = handler; };
+
+prototypeAccessors.formatter.get = function () { return this._formatter };
+prototypeAccessors.formatter.set = function (formatter) { this._formatter = formatter; };
+
+prototypeAccessors.silentTranslationWarn.get = function () { return this._silentTranslationWarn };
+prototypeAccessors.silentTranslationWarn.set = function (silent) { this._silentTranslationWarn = silent; };
+
+prototypeAccessors.silentFallbackWarn.get = function () { return this._silentFallbackWarn };
+prototypeAccessors.silentFallbackWarn.set = function (silent) { this._silentFallbackWarn = silent; };
+
+prototypeAccessors.preserveDirectiveContent.get = function () { return this._preserveDirectiveContent };
+prototypeAccessors.preserveDirectiveContent.set = function (preserve) { this._preserveDirectiveContent = preserve; };
+
+prototypeAccessors.warnHtmlInMessage.get = function () { return this._warnHtmlInMessage };
+prototypeAccessors.warnHtmlInMessage.set = function (level) {
+    var this$1 = this;
+
+  var orgLevel = this._warnHtmlInMessage;
+  this._warnHtmlInMessage = level;
+  if (orgLevel !== level && (level === 'warn' || level === 'error')) {
+    var messages = this._getMessages();
+    Object.keys(messages).forEach(function (locale) {
+      this$1._checkLocaleMessage(locale, this$1._warnHtmlInMessage, messages[locale]);
+    });
+  }
+};
+
+prototypeAccessors.postTranslation.get = function () { return this._postTranslation };
+prototypeAccessors.postTranslation.set = function (handler) { this._postTranslation = handler; };
+
+VueI18n.prototype._getMessages = function _getMessages () { return this._vm.messages };
+VueI18n.prototype._getDateTimeFormats = function _getDateTimeFormats () { return this._vm.dateTimeFormats };
+VueI18n.prototype._getNumberFormats = function _getNumberFormats () { return this._vm.numberFormats };
+
+VueI18n.prototype._warnDefault = function _warnDefault (locale, key, result, vm, values, interpolateMode) {
+  if (!isNull(result)) { return result }
+  if (this._missing) {
+    var missingRet = this._missing.apply(null, [locale, key, vm, values]);
+    if (isString(missingRet)) {
+      return missingRet
+    }
+  } else {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key)) {
+      warn(
+        "Cannot translate the value of keypath '" + key + "'. " +
+        'Use the value of keypath as default.'
+      );
+    }
+  }
+
+  if (this._formatFallbackMessages) {
+    var parsedArgs = parseArgs.apply(void 0, values);
+    return this._render(key, interpolateMode, parsedArgs.params, key)
+  } else {
+    return key
+  }
+};
+
+VueI18n.prototype._isFallbackRoot = function _isFallbackRoot (val) {
+  return !val && !isNull(this._root) && this._fallbackRoot
+};
+
+VueI18n.prototype._isSilentFallbackWarn = function _isSilentFallbackWarn (key) {
+  return this._silentFallbackWarn instanceof RegExp
+    ? this._silentFallbackWarn.test(key)
+    : this._silentFallbackWarn
+};
+
+VueI18n.prototype._isSilentFallback = function _isSilentFallback (locale, key) {
+  return this._isSilentFallbackWarn(key) && (this._isFallbackRoot() || locale !== this.fallbackLocale)
+};
+
+VueI18n.prototype._isSilentTranslationWarn = function _isSilentTranslationWarn (key) {
+  return this._silentTranslationWarn instanceof RegExp
+    ? this._silentTranslationWarn.test(key)
+    : this._silentTranslationWarn
+};
+
+VueI18n.prototype._interpolate = function _interpolate (
+  locale,
+  message,
+  key,
+  host,
+  interpolateMode,
+  values,
+  visitedLinkStack
+) {
+  if (!message) { return null }
+
+  var pathRet = this._path.getPathValue(message, key);
+  if (isArray(pathRet) || isPlainObject(pathRet)) { return pathRet }
+
+  var ret;
+  if (isNull(pathRet)) {
+    /* istanbul ignore else */
+    if (isPlainObject(message)) {
+      ret = message[key];
+      if (!(isString(ret) || isFunction(ret))) {
+        if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+          warn(("Value of key '" + key + "' is not a string or function !"));
+        }
+        return null
+      }
+    } else {
+      return null
+    }
+  } else {
+    /* istanbul ignore else */
+    if (isString(pathRet) || isFunction(pathRet)) {
+      ret = pathRet;
+    } else {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+        warn(("Value of key '" + key + "' is not a string or function!"));
+      }
+      return null
+    }
+  }
+
+  // Check for the existence of links within the translated string
+  if (isString(ret) && (ret.indexOf('@:') >= 0 || ret.indexOf('@.') >= 0)) {
+    ret = this._link(locale, message, ret, host, 'raw', values, visitedLinkStack);
+  }
+
+  return this._render(ret, interpolateMode, values, key)
+};
+
+VueI18n.prototype._link = function _link (
+  locale,
+  message,
+  str,
+  host,
+  interpolateMode,
+  values,
+  visitedLinkStack
+) {
+  var ret = str;
+
+  // Match all the links within the local
+  // We are going to replace each of
+  // them with its translation
+  var matches = ret.match(linkKeyMatcher);
+  for (var idx in matches) {
+    // ie compatible: filter custom array
+    // prototype method
+    if (!matches.hasOwnProperty(idx)) {
+      continue
+    }
+    var link = matches[idx];
+    var linkKeyPrefixMatches = link.match(linkKeyPrefixMatcher);
+    var linkPrefix = linkKeyPrefixMatches[0];
+      var formatterName = linkKeyPrefixMatches[1];
+
+    // Remove the leading @:, @.case: and the brackets
+    var linkPlaceholder = link.replace(linkPrefix, '').replace(bracketsMatcher, '');
+
+    if (includes(visitedLinkStack, linkPlaceholder)) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn(("Circular reference found. \"" + link + "\" is already visited in the chain of " + (visitedLinkStack.reverse().join(' <- '))));
+      }
+      return ret
+    }
+    visitedLinkStack.push(linkPlaceholder);
+
+    // Translate the link
+    var translated = this._interpolate(
+      locale, message, linkPlaceholder, host,
+      interpolateMode === 'raw' ? 'string' : interpolateMode,
+      interpolateMode === 'raw' ? undefined : values,
+      visitedLinkStack
+    );
+
+    if (this._isFallbackRoot(translated)) {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(linkPlaceholder)) {
+        warn(("Fall back to translate the link placeholder '" + linkPlaceholder + "' with root locale."));
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      var root = this._root.$i18n;
+      translated = root._translate(
+        root._getMessages(), root.locale, root.fallbackLocale,
+        linkPlaceholder, host, interpolateMode, values
+      );
+    }
+    translated = this._warnDefault(
+      locale, linkPlaceholder, translated, host,
+      isArray(values) ? values : [values],
+      interpolateMode
+    );
+
+    if (this._modifiers.hasOwnProperty(formatterName)) {
+      translated = this._modifiers[formatterName](translated);
+    } else if (defaultModifiers.hasOwnProperty(formatterName)) {
+      translated = defaultModifiers[formatterName](translated);
+    }
+
+    visitedLinkStack.pop();
+
+    // Replace the link with the translated
+    ret = !translated ? ret : ret.replace(link, translated);
+  }
+
+  return ret
+};
+
+VueI18n.prototype._createMessageContext = function _createMessageContext (values) {
+  var _list = isArray(values) ? values : [];
+  var _named = isObject(values) ? values : {};
+  var list = function (index) { return _list[index]; };
+  var named = function (key) { return _named[key]; };
+  return {
+    list: list,
+    named: named
+  }
+};
+
+VueI18n.prototype._render = function _render (message, interpolateMode, values, path) {
+  if (isFunction(message)) {
+    return message(this._createMessageContext(values))
+  }
+
+  var ret = this._formatter.interpolate(message, values, path);
+
+  // If the custom formatter refuses to work - apply the default one
+  if (!ret) {
+    ret = defaultFormatter.interpolate(message, values, path);
+  }
+
+  // if interpolateMode is **not** 'string' ('row'),
+  // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
+  return interpolateMode === 'string' && !isString(ret) ? ret.join('') : ret
+};
+
+VueI18n.prototype._appendItemToChain = function _appendItemToChain (chain, item, blocks) {
+  var follow = false;
+  if (!includes(chain, item)) {
+    follow = true;
+    if (item) {
+      follow = item[item.length - 1] !== '!';
+      item = item.replace(/!/g, '');
+      chain.push(item);
+      if (blocks && blocks[item]) {
+        follow = blocks[item];
+      }
+    }
+  }
+  return follow
+};
+
+VueI18n.prototype._appendLocaleToChain = function _appendLocaleToChain (chain, locale, blocks) {
+  var follow;
+  var tokens = locale.split('-');
+  do {
+    var item = tokens.join('-');
+    follow = this._appendItemToChain(chain, item, blocks);
+    tokens.splice(-1, 1);
+  } while (tokens.length && (follow === true))
+  return follow
+};
+
+VueI18n.prototype._appendBlockToChain = function _appendBlockToChain (chain, block, blocks) {
+  var follow = true;
+  for (var i = 0; (i < block.length) && (isBoolean(follow)); i++) {
+    var locale = block[i];
+    if (isString(locale)) {
+      follow = this._appendLocaleToChain(chain, locale, blocks);
+    }
+  }
+  return follow
+};
+
+VueI18n.prototype._getLocaleChain = function _getLocaleChain (start, fallbackLocale) {
+  if (start === '') { return [] }
+
+  if (!this._localeChainCache) {
+    this._localeChainCache = {};
+  }
+
+  var chain = this._localeChainCache[start];
+  if (!chain) {
+    if (!fallbackLocale) {
+      fallbackLocale = this.fallbackLocale;
+    }
+    chain = [];
+
+    // first block defined by start
+    var block = [start];
+
+    // while any intervening block found
+    while (isArray(block)) {
+      block = this._appendBlockToChain(
+        chain,
+        block,
+        fallbackLocale
+      );
+    }
+
+    // last block defined by default
+    var defaults;
+    if (isArray(fallbackLocale)) {
+      defaults = fallbackLocale;
+    } else if (isObject(fallbackLocale)) {
+      /* $FlowFixMe */
+      if (fallbackLocale['default']) {
+        defaults = fallbackLocale['default'];
+      } else {
+        defaults = null;
+      }
+    } else {
+      defaults = fallbackLocale;
+    }
+
+    // convert defaults to array
+    if (isString(defaults)) {
+      block = [defaults];
+    } else {
+      block = defaults;
+    }
+    if (block) {
+      this._appendBlockToChain(
+        chain,
+        block,
+        null
+      );
+    }
+    this._localeChainCache[start] = chain;
+  }
+  return chain
+};
+
+VueI18n.prototype._translate = function _translate (
+  messages,
+  locale,
+  fallback,
+  key,
+  host,
+  interpolateMode,
+  args
+) {
+  var chain = this._getLocaleChain(locale, fallback);
+  var res;
+  for (var i = 0; i < chain.length; i++) {
+    var step = chain[i];
+    res =
+      this._interpolate(step, messages[step], key, host, interpolateMode, args, [key]);
+    if (!isNull(res)) {
+      if (step !== locale && process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(("Fall back to translate the keypath '" + key + "' with '" + step + "' locale."));
+      }
+      return res
+    }
+  }
+  return null
+};
+
+VueI18n.prototype._t = function _t (key, _locale, messages, host) {
+    var ref;
+
+    var values = [], len = arguments.length - 4;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 4 ];
+  if (!key) { return '' }
+
+  var parsedArgs = parseArgs.apply(void 0, values);
+  var locale = parsedArgs.locale || _locale;
+
+  var ret = this._translate(
+    messages, locale, this.fallbackLocale, key,
+    host, 'string', parsedArgs.params
+  );
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+      warn(("Fall back to translate the keypath '" + key + "' with root locale."));
+    }
+    /* istanbul ignore if */
+    if (!this._root) { throw Error('unexpected error') }
+    return (ref = this._root).$t.apply(ref, [ key ].concat( values ))
+  } else {
+    ret = this._warnDefault(locale, key, ret, host, values, 'string');
+    if (this._postTranslation && ret !== null && ret !== undefined) {
+      ret = this._postTranslation(ret, key);
+    }
+    return ret
+  }
+};
+
+VueI18n.prototype.t = function t (key) {
+    var ref;
+
+    var values = [], len = arguments.length - 1;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 1 ];
+  return (ref = this)._t.apply(ref, [ key, this.locale, this._getMessages(), null ].concat( values ))
+};
+
+VueI18n.prototype._i = function _i (key, locale, messages, host, values) {
+  var ret =
+    this._translate(messages, locale, this.fallbackLocale, key, host, 'raw', values);
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key)) {
+      warn(("Fall back to interpolate the keypath '" + key + "' with root locale."));
+    }
+    if (!this._root) { throw Error('unexpected error') }
+    return this._root.$i18n.i(key, locale, values)
+  } else {
+    return this._warnDefault(locale, key, ret, host, [values], 'raw')
+  }
+};
+
+VueI18n.prototype.i = function i (key, locale, values) {
+  /* istanbul ignore if */
+  if (!key) { return '' }
+
+  if (!isString(locale)) {
+    locale = this.locale;
+  }
+
+  return this._i(key, locale, this._getMessages(), null, values)
+};
+
+VueI18n.prototype._tc = function _tc (
+  key,
+  _locale,
+  messages,
+  host,
+  choice
+) {
+    var ref;
+
+    var values = [], len = arguments.length - 5;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 5 ];
+  if (!key) { return '' }
+  if (choice === undefined) {
+    choice = 1;
+  }
+
+  var predefined = { 'count': choice, 'n': choice };
+  var parsedArgs = parseArgs.apply(void 0, values);
+  parsedArgs.params = Object.assign(predefined, parsedArgs.params);
+  values = parsedArgs.locale === null ? [parsedArgs.params] : [parsedArgs.locale, parsedArgs.params];
+  return this.fetchChoice((ref = this)._t.apply(ref, [ key, _locale, messages, host ].concat( values )), choice)
+};
+
+VueI18n.prototype.fetchChoice = function fetchChoice (message, choice) {
+  /* istanbul ignore if */
+  if (!message && !isString(message)) { return null }
+  var choices = message.split('|');
+
+  choice = this.getChoiceIndex(choice, choices.length);
+  if (!choices[choice]) { return message }
+  return choices[choice].trim()
+};
+
+VueI18n.prototype.tc = function tc (key, choice) {
+    var ref;
+
+    var values = [], len = arguments.length - 2;
+    while ( len-- > 0 ) values[ len ] = arguments[ len + 2 ];
+  return (ref = this)._tc.apply(ref, [ key, this.locale, this._getMessages(), null, choice ].concat( values ))
+};
+
+VueI18n.prototype._te = function _te (key, locale, messages) {
+    var args = [], len = arguments.length - 3;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 3 ];
+
+  var _locale = parseArgs.apply(void 0, args).locale || locale;
+  return this._exist(messages[_locale], key)
+};
+
+VueI18n.prototype.te = function te (key, locale) {
+  return this._te(key, this.locale, this._getMessages(), locale)
+};
+
+VueI18n.prototype.getLocaleMessage = function getLocaleMessage (locale) {
+  return looseClone(this._vm.messages[locale] || {})
+};
+
+VueI18n.prototype.setLocaleMessage = function setLocaleMessage (locale, message) {
+  if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+    this._checkLocaleMessage(locale, this._warnHtmlInMessage, message);
+  }
+  this._vm.$set(this._vm.messages, locale, message);
+};
+
+VueI18n.prototype.mergeLocaleMessage = function mergeLocaleMessage (locale, message) {
+  if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+    this._checkLocaleMessage(locale, this._warnHtmlInMessage, message);
+  }
+  this._vm.$set(this._vm.messages, locale, merge({}, this._vm.messages[locale] || {}, message));
+};
+
+VueI18n.prototype.getDateTimeFormat = function getDateTimeFormat (locale) {
+  return looseClone(this._vm.dateTimeFormats[locale] || {})
+};
+
+VueI18n.prototype.setDateTimeFormat = function setDateTimeFormat (locale, format) {
+  this._vm.$set(this._vm.dateTimeFormats, locale, format);
+  this._clearDateTimeFormat(locale, format);
+};
+
+VueI18n.prototype.mergeDateTimeFormat = function mergeDateTimeFormat (locale, format) {
+  this._vm.$set(this._vm.dateTimeFormats, locale, merge(this._vm.dateTimeFormats[locale] || {}, format));
+  this._clearDateTimeFormat(locale, format);
+};
+
+VueI18n.prototype._clearDateTimeFormat = function _clearDateTimeFormat (locale, format) {
+  for (var key in format) {
+    var id = locale + "__" + key;
+
+    if (!this._dateTimeFormatters.hasOwnProperty(id)) {
+      continue
+    }
+
+    delete this._dateTimeFormatters[id];
+  }
+};
+
+VueI18n.prototype._localizeDateTime = function _localizeDateTime (
+  value,
+  locale,
+  fallback,
+  dateTimeFormats,
+  key
+) {
+  var _locale = locale;
+  var formats = dateTimeFormats[_locale];
+
+  var chain = this._getLocaleChain(locale, fallback);
+  for (var i = 0; i < chain.length; i++) {
+    var current = _locale;
+    var step = chain[i];
+    formats = dateTimeFormats[step];
+    _locale = step;
+    // fallback locale
+    if (isNull(formats) || isNull(formats[key])) {
+      if (step !== locale && process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(("Fall back to '" + step + "' datetime formats from '" + current + "' datetime formats."));
+      }
+    } else {
+      break
+    }
+  }
+
+  if (isNull(formats) || isNull(formats[key])) {
+    return null
+  } else {
+    var format = formats[key];
+    var id = _locale + "__" + key;
+    var formatter = this._dateTimeFormatters[id];
+    if (!formatter) {
+      formatter = this._dateTimeFormatters[id] = new Intl.DateTimeFormat(_locale, format);
+    }
+    return formatter.format(value)
+  }
+};
+
+VueI18n.prototype._d = function _d (value, locale, key) {
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && !VueI18n.availabilities.dateTimeFormat) {
+    warn('Cannot format a Date value due to not supported Intl.DateTimeFormat.');
+    return ''
+  }
+
+  if (!key) {
+    return new Intl.DateTimeFormat(locale).format(value)
+  }
+
+  var ret =
+    this._localizeDateTime(value, locale, this.fallbackLocale, this._getDateTimeFormats(), key);
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+      warn(("Fall back to datetime localization of root: key '" + key + "'."));
+    }
+    /* istanbul ignore if */
+    if (!this._root) { throw Error('unexpected error') }
+    return this._root.$i18n.d(value, key, locale)
+  } else {
+    return ret || ''
+  }
+};
+
+VueI18n.prototype.d = function d (value) {
+    var args = [], len = arguments.length - 1;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+
+  var locale = this.locale;
+  var key = null;
+
+  if (args.length === 1) {
+    if (isString(args[0])) {
+      key = args[0];
+    } else if (isObject(args[0])) {
+      if (args[0].locale) {
+        locale = args[0].locale;
+      }
+      if (args[0].key) {
+        key = args[0].key;
+      }
+    }
+  } else if (args.length === 2) {
+    if (isString(args[0])) {
+      key = args[0];
+    }
+    if (isString(args[1])) {
+      locale = args[1];
+    }
+  }
+
+  return this._d(value, locale, key)
+};
+
+VueI18n.prototype.getNumberFormat = function getNumberFormat (locale) {
+  return looseClone(this._vm.numberFormats[locale] || {})
+};
+
+VueI18n.prototype.setNumberFormat = function setNumberFormat (locale, format) {
+  this._vm.$set(this._vm.numberFormats, locale, format);
+  this._clearNumberFormat(locale, format);
+};
+
+VueI18n.prototype.mergeNumberFormat = function mergeNumberFormat (locale, format) {
+  this._vm.$set(this._vm.numberFormats, locale, merge(this._vm.numberFormats[locale] || {}, format));
+  this._clearNumberFormat(locale, format);
+};
+
+VueI18n.prototype._clearNumberFormat = function _clearNumberFormat (locale, format) {
+  for (var key in format) {
+    var id = locale + "__" + key;
+
+    if (!this._numberFormatters.hasOwnProperty(id)) {
+      continue
+    }
+
+    delete this._numberFormatters[id];
+  }
+};
+
+VueI18n.prototype._getNumberFormatter = function _getNumberFormatter (
+  value,
+  locale,
+  fallback,
+  numberFormats,
+  key,
+  options
+) {
+  var _locale = locale;
+  var formats = numberFormats[_locale];
+
+  var chain = this._getLocaleChain(locale, fallback);
+  for (var i = 0; i < chain.length; i++) {
+    var current = _locale;
+    var step = chain[i];
+    formats = numberFormats[step];
+    _locale = step;
+    // fallback locale
+    if (isNull(formats) || isNull(formats[key])) {
+      if (step !== locale && process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(("Fall back to '" + step + "' number formats from '" + current + "' number formats."));
+      }
+    } else {
+      break
+    }
+  }
+
+  if (isNull(formats) || isNull(formats[key])) {
+    return null
+  } else {
+    var format = formats[key];
+
+    var formatter;
+    if (options) {
+      // If options specified - create one time number formatter
+      formatter = new Intl.NumberFormat(_locale, Object.assign({}, format, options));
+    } else {
+      var id = _locale + "__" + key;
+      formatter = this._numberFormatters[id];
+      if (!formatter) {
+        formatter = this._numberFormatters[id] = new Intl.NumberFormat(_locale, format);
+      }
+    }
+    return formatter
+  }
+};
+
+VueI18n.prototype._n = function _n (value, locale, key, options) {
+  /* istanbul ignore if */
+  if (!VueI18n.availabilities.numberFormat) {
+    if (process.env.NODE_ENV !== 'production') {
+      warn('Cannot format a Number value due to not supported Intl.NumberFormat.');
+    }
+    return ''
+  }
+
+  if (!key) {
+    var nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options);
+    return nf.format(value)
+  }
+
+  var formatter = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
+  var ret = formatter && formatter.format(value);
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+      warn(("Fall back to number localization of root: key '" + key + "'."));
+    }
+    /* istanbul ignore if */
+    if (!this._root) { throw Error('unexpected error') }
+    return this._root.$i18n.n(value, Object.assign({}, { key: key, locale: locale }, options))
+  } else {
+    return ret || ''
+  }
+};
+
+VueI18n.prototype.n = function n (value) {
+    var args = [], len = arguments.length - 1;
+    while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+
+  var locale = this.locale;
+  var key = null;
+  var options = null;
+
+  if (args.length === 1) {
+    if (isString(args[0])) {
+      key = args[0];
+    } else if (isObject(args[0])) {
+      if (args[0].locale) {
+        locale = args[0].locale;
+      }
+      if (args[0].key) {
+        key = args[0].key;
+      }
+
+      // Filter out number format options only
+      options = Object.keys(args[0]).reduce(function (acc, key) {
+          var obj;
+
+        if (includes(numberFormatKeys, key)) {
+          return Object.assign({}, acc, ( obj = {}, obj[key] = args[0][key], obj ))
+        }
+        return acc
+      }, null);
+    }
+  } else if (args.length === 2) {
+    if (isString(args[0])) {
+      key = args[0];
+    }
+    if (isString(args[1])) {
+      locale = args[1];
+    }
+  }
+
+  return this._n(value, locale, key, options)
+};
+
+VueI18n.prototype._ntp = function _ntp (value, locale, key, options) {
+  /* istanbul ignore if */
+  if (!VueI18n.availabilities.numberFormat) {
+    if (process.env.NODE_ENV !== 'production') {
+      warn('Cannot format to parts a Number value due to not supported Intl.NumberFormat.');
+    }
+    return []
+  }
+
+  if (!key) {
+    var nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options);
+    return nf.formatToParts(value)
+  }
+
+  var formatter = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
+  var ret = formatter && formatter.formatToParts(value);
+  if (this._isFallbackRoot(ret)) {
+    if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key)) {
+      warn(("Fall back to format number to parts of root: key '" + key + "' ."));
+    }
+    /* istanbul ignore if */
+    if (!this._root) { throw Error('unexpected error') }
+    return this._root.$i18n._ntp(value, locale, key, options)
+  } else {
+    return ret || []
+  }
+};
+
+Object.defineProperties( VueI18n.prototype, prototypeAccessors );
+
+var availabilities;
+// $FlowFixMe
+Object.defineProperty(VueI18n, 'availabilities', {
+  get: function get () {
+    if (!availabilities) {
+      var intlDefined = typeof Intl !== 'undefined';
+      availabilities = {
+        dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
+        numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
+      };
+    }
+
+    return availabilities
+  }
+});
+
+VueI18n.install = install;
+VueI18n.version = '8.21.0';
+
+export default VueI18n;

+ 2157 - 0
plugin/vue-i18n/dist/vue-i18n.js

@@ -0,0 +1,2157 @@
+/*!
+ * vue-i18n v8.21.0 
+ * (c) 2020 kazuya kawaguchi
+ * Released under the MIT License.
+ */
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+  typeof define === 'function' && define.amd ? define(factory) :
+  (global.VueI18n = factory());
+}(this, (function () { 'use strict';
+
+  /*  */
+
+  /**
+   * constants
+   */
+
+  var numberFormatKeys = [
+    'style',
+    'currency',
+    'currencyDisplay',
+    'useGrouping',
+    'minimumIntegerDigits',
+    'minimumFractionDigits',
+    'maximumFractionDigits',
+    'minimumSignificantDigits',
+    'maximumSignificantDigits',
+    'localeMatcher',
+    'formatMatcher',
+    'unit'
+  ];
+
+  /**
+   * utilities
+   */
+
+  function warn (msg, err) {
+    if (typeof console !== 'undefined') {
+      console.warn('[vue-i18n] ' + msg);
+      /* istanbul ignore if */
+      if (err) {
+        console.warn(err.stack);
+      }
+    }
+  }
+
+  function error (msg, err) {
+    if (typeof console !== 'undefined') {
+      console.error('[vue-i18n] ' + msg);
+      /* istanbul ignore if */
+      if (err) {
+        console.error(err.stack);
+      }
+    }
+  }
+
+  var isArray = Array.isArray;
+
+  function isObject (obj) {
+    return obj !== null && typeof obj === 'object'
+  }
+
+  function isBoolean (val) {
+    return typeof val === 'boolean'
+  }
+
+  function isString (val) {
+    return typeof val === 'string'
+  }
+
+  var toString = Object.prototype.toString;
+  var OBJECT_STRING = '[object Object]';
+  function isPlainObject (obj) {
+    return toString.call(obj) === OBJECT_STRING
+  }
+
+  function isNull (val) {
+    return val === null || val === undefined
+  }
+
+  function isFunction (val) {
+    return typeof val === 'function'
+  }
+
+  function parseArgs () {
+    var args = [], len = arguments.length;
+    while ( len-- ) args[ len ] = arguments[ len ];
+
+    var locale = null;
+    var params = null;
+    if (args.length === 1) {
+      if (isObject(args[0]) || isArray(args[0])) {
+        params = args[0];
+      } else if (typeof args[0] === 'string') {
+        locale = args[0];
+      }
+    } else if (args.length === 2) {
+      if (typeof args[0] === 'string') {
+        locale = args[0];
+      }
+      /* istanbul ignore if */
+      if (isObject(args[1]) || isArray(args[1])) {
+        params = args[1];
+      }
+    }
+
+    return { locale: locale, params: params }
+  }
+
+  function looseClone (obj) {
+    return JSON.parse(JSON.stringify(obj))
+  }
+
+  function remove (arr, item) {
+    if (arr.length) {
+      var index = arr.indexOf(item);
+      if (index > -1) {
+        return arr.splice(index, 1)
+      }
+    }
+  }
+
+  function includes (arr, item) {
+    return !!~arr.indexOf(item)
+  }
+
+  var hasOwnProperty = Object.prototype.hasOwnProperty;
+  function hasOwn (obj, key) {
+    return hasOwnProperty.call(obj, key)
+  }
+
+  function merge (target) {
+    var arguments$1 = arguments;
+
+    var output = Object(target);
+    for (var i = 1; i < arguments.length; i++) {
+      var source = arguments$1[i];
+      if (source !== undefined && source !== null) {
+        var key = (void 0);
+        for (key in source) {
+          if (hasOwn(source, key)) {
+            if (isObject(source[key])) {
+              output[key] = merge(output[key], source[key]);
+            } else {
+              output[key] = source[key];
+            }
+          }
+        }
+      }
+    }
+    return output
+  }
+
+  function looseEqual (a, b) {
+    if (a === b) { return true }
+    var isObjectA = isObject(a);
+    var isObjectB = isObject(b);
+    if (isObjectA && isObjectB) {
+      try {
+        var isArrayA = isArray(a);
+        var isArrayB = isArray(b);
+        if (isArrayA && isArrayB) {
+          return a.length === b.length && a.every(function (e, i) {
+            return looseEqual(e, b[i])
+          })
+        } else if (!isArrayA && !isArrayB) {
+          var keysA = Object.keys(a);
+          var keysB = Object.keys(b);
+          return keysA.length === keysB.length && keysA.every(function (key) {
+            return looseEqual(a[key], b[key])
+          })
+        } else {
+          /* istanbul ignore next */
+          return false
+        }
+      } catch (e) {
+        /* istanbul ignore next */
+        return false
+      }
+    } else if (!isObjectA && !isObjectB) {
+      return String(a) === String(b)
+    } else {
+      return false
+    }
+  }
+
+  /*  */
+
+  function extend (Vue) {
+    if (!Vue.prototype.hasOwnProperty('$i18n')) {
+      // $FlowFixMe
+      Object.defineProperty(Vue.prototype, '$i18n', {
+        get: function get () { return this._i18n }
+      });
+    }
+
+    Vue.prototype.$t = function (key) {
+      var values = [], len = arguments.length - 1;
+      while ( len-- > 0 ) values[ len ] = arguments[ len + 1 ];
+
+      var i18n = this.$i18n;
+      return i18n._t.apply(i18n, [ key, i18n.locale, i18n._getMessages(), this ].concat( values ))
+    };
+
+    Vue.prototype.$tc = function (key, choice) {
+      var values = [], len = arguments.length - 2;
+      while ( len-- > 0 ) values[ len ] = arguments[ len + 2 ];
+
+      var i18n = this.$i18n;
+      return i18n._tc.apply(i18n, [ key, i18n.locale, i18n._getMessages(), this, choice ].concat( values ))
+    };
+
+    Vue.prototype.$te = function (key, locale) {
+      var i18n = this.$i18n;
+      return i18n._te(key, i18n.locale, i18n._getMessages(), locale)
+    };
+
+    Vue.prototype.$d = function (value) {
+      var ref;
+
+      var args = [], len = arguments.length - 1;
+      while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+      return (ref = this.$i18n).d.apply(ref, [ value ].concat( args ))
+    };
+
+    Vue.prototype.$n = function (value) {
+      var ref;
+
+      var args = [], len = arguments.length - 1;
+      while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+      return (ref = this.$i18n).n.apply(ref, [ value ].concat( args ))
+    };
+  }
+
+  /*  */
+
+  var mixin = {
+    beforeCreate: function beforeCreate () {
+      var options = this.$options;
+      options.i18n = options.i18n || (options.__i18n ? {} : null);
+
+      if (options.i18n) {
+        if (options.i18n instanceof VueI18n) {
+          // init locale messages via custom blocks
+          if (options.__i18n) {
+            try {
+              var localeMessages = {};
+              options.__i18n.forEach(function (resource) {
+                localeMessages = merge(localeMessages, JSON.parse(resource));
+              });
+              Object.keys(localeMessages).forEach(function (locale) {
+                options.i18n.mergeLocaleMessage(locale, localeMessages[locale]);
+              });
+            } catch (e) {
+              {
+                error("Cannot parse locale messages via custom blocks.", e);
+              }
+            }
+          }
+          this._i18n = options.i18n;
+          this._i18nWatcher = this._i18n.watchI18nData();
+        } else if (isPlainObject(options.i18n)) {
+          var rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
+            ? this.$root.$i18n
+            : null;
+          // component local i18n
+          if (rootI18n) {
+            options.i18n.root = this.$root;
+            options.i18n.formatter = rootI18n.formatter;
+            options.i18n.fallbackLocale = rootI18n.fallbackLocale;
+            options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages;
+            options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn;
+            options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn;
+            options.i18n.pluralizationRules = rootI18n.pluralizationRules;
+            options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent;
+          }
+
+          // init locale messages via custom blocks
+          if (options.__i18n) {
+            try {
+              var localeMessages$1 = {};
+              options.__i18n.forEach(function (resource) {
+                localeMessages$1 = merge(localeMessages$1, JSON.parse(resource));
+              });
+              options.i18n.messages = localeMessages$1;
+            } catch (e) {
+              {
+                warn("Cannot parse locale messages via custom blocks.", e);
+              }
+            }
+          }
+
+          var ref = options.i18n;
+          var sharedMessages = ref.sharedMessages;
+          if (sharedMessages && isPlainObject(sharedMessages)) {
+            options.i18n.messages = merge(options.i18n.messages, sharedMessages);
+          }
+
+          this._i18n = new VueI18n(options.i18n);
+          this._i18nWatcher = this._i18n.watchI18nData();
+
+          if (options.i18n.sync === undefined || !!options.i18n.sync) {
+            this._localeWatcher = this.$i18n.watchLocale();
+          }
+
+          if (rootI18n) {
+            rootI18n.onComponentInstanceCreated(this._i18n);
+          }
+        } else {
+          {
+            warn("Cannot be interpreted 'i18n' option.");
+          }
+        }
+      } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+        // root i18n
+        this._i18n = this.$root.$i18n;
+      } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+        // parent i18n
+        this._i18n = options.parent.$i18n;
+      }
+    },
+
+    beforeMount: function beforeMount () {
+      var options = this.$options;
+      options.i18n = options.i18n || (options.__i18n ? {} : null);
+
+      if (options.i18n) {
+        if (options.i18n instanceof VueI18n) {
+          // init locale messages via custom blocks
+          this._i18n.subscribeDataChanging(this);
+          this._subscribing = true;
+        } else if (isPlainObject(options.i18n)) {
+          this._i18n.subscribeDataChanging(this);
+          this._subscribing = true;
+        } else {
+          {
+            warn("Cannot be interpreted 'i18n' option.");
+          }
+        }
+      } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+        this._i18n.subscribeDataChanging(this);
+        this._subscribing = true;
+      } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+        this._i18n.subscribeDataChanging(this);
+        this._subscribing = true;
+      }
+    },
+
+    beforeDestroy: function beforeDestroy () {
+      if (!this._i18n) { return }
+
+      var self = this;
+      this.$nextTick(function () {
+        if (self._subscribing) {
+          self._i18n.unsubscribeDataChanging(self);
+          delete self._subscribing;
+        }
+
+        if (self._i18nWatcher) {
+          self._i18nWatcher();
+          self._i18n.destroyVM();
+          delete self._i18nWatcher;
+        }
+
+        if (self._localeWatcher) {
+          self._localeWatcher();
+          delete self._localeWatcher;
+        }
+      });
+    }
+  };
+
+  /*  */
+
+  var interpolationComponent = {
+    name: 'i18n',
+    functional: true,
+    props: {
+      tag: {
+        type: [String, Boolean, Object],
+        default: 'span'
+      },
+      path: {
+        type: String,
+        required: true
+      },
+      locale: {
+        type: String
+      },
+      places: {
+        type: [Array, Object]
+      }
+    },
+    render: function render (h, ref) {
+      var data = ref.data;
+      var parent = ref.parent;
+      var props = ref.props;
+      var slots = ref.slots;
+
+      var $i18n = parent.$i18n;
+      if (!$i18n) {
+        {
+          warn('Cannot find VueI18n instance!');
+        }
+        return
+      }
+
+      var path = props.path;
+      var locale = props.locale;
+      var places = props.places;
+      var params = slots();
+      var children = $i18n.i(
+        path,
+        locale,
+        onlyHasDefaultPlace(params) || places
+          ? useLegacyPlaces(params.default, places)
+          : params
+      );
+
+      var tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span';
+      return tag ? h(tag, data, children) : children
+    }
+  };
+
+  function onlyHasDefaultPlace (params) {
+    var prop;
+    for (prop in params) {
+      if (prop !== 'default') { return false }
+    }
+    return Boolean(prop)
+  }
+
+  function useLegacyPlaces (children, places) {
+    var params = places ? createParamsFromPlaces(places) : {};
+
+    if (!children) { return params }
+
+    // Filter empty text nodes
+    children = children.filter(function (child) {
+      return child.tag || child.text.trim() !== ''
+    });
+
+    var everyPlace = children.every(vnodeHasPlaceAttribute);
+    if (everyPlace) {
+      warn('`place` attribute is deprecated in next major version. Please switch to Vue slots.');
+    }
+
+    return children.reduce(
+      everyPlace ? assignChildPlace : assignChildIndex,
+      params
+    )
+  }
+
+  function createParamsFromPlaces (places) {
+    {
+      warn('`places` prop is deprecated in next major version. Please switch to Vue slots.');
+    }
+
+    return Array.isArray(places)
+      ? places.reduce(assignChildIndex, {})
+      : Object.assign({}, places)
+  }
+
+  function assignChildPlace (params, child) {
+    if (child.data && child.data.attrs && child.data.attrs.place) {
+      params[child.data.attrs.place] = child;
+    }
+    return params
+  }
+
+  function assignChildIndex (params, child, index) {
+    params[index] = child;
+    return params
+  }
+
+  function vnodeHasPlaceAttribute (vnode) {
+    return Boolean(vnode.data && vnode.data.attrs && vnode.data.attrs.place)
+  }
+
+  /*  */
+
+  var numberComponent = {
+    name: 'i18n-n',
+    functional: true,
+    props: {
+      tag: {
+        type: [String, Boolean, Object],
+        default: 'span'
+      },
+      value: {
+        type: Number,
+        required: true
+      },
+      format: {
+        type: [String, Object]
+      },
+      locale: {
+        type: String
+      }
+    },
+    render: function render (h, ref) {
+      var props = ref.props;
+      var parent = ref.parent;
+      var data = ref.data;
+
+      var i18n = parent.$i18n;
+
+      if (!i18n) {
+        {
+          warn('Cannot find VueI18n instance!');
+        }
+        return null
+      }
+
+      var key = null;
+      var options = null;
+
+      if (isString(props.format)) {
+        key = props.format;
+      } else if (isObject(props.format)) {
+        if (props.format.key) {
+          key = props.format.key;
+        }
+
+        // Filter out number format options only
+        options = Object.keys(props.format).reduce(function (acc, prop) {
+          var obj;
+
+          if (includes(numberFormatKeys, prop)) {
+            return Object.assign({}, acc, ( obj = {}, obj[prop] = props.format[prop], obj ))
+          }
+          return acc
+        }, null);
+      }
+
+      var locale = props.locale || i18n.locale;
+      var parts = i18n._ntp(props.value, locale, key, options);
+
+      var values = parts.map(function (part, index) {
+        var obj;
+
+        var slot = data.scopedSlots && data.scopedSlots[part.type];
+        return slot ? slot(( obj = {}, obj[part.type] = part.value, obj.index = index, obj.parts = parts, obj )) : part.value
+      });
+
+      var tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span';
+      return tag
+        ? h(tag, {
+          attrs: data.attrs,
+          'class': data['class'],
+          staticClass: data.staticClass
+        }, values)
+        : values
+    }
+  };
+
+  /*  */
+
+  function bind (el, binding, vnode) {
+    if (!assert(el, vnode)) { return }
+
+    t(el, binding, vnode);
+  }
+
+  function update (el, binding, vnode, oldVNode) {
+    if (!assert(el, vnode)) { return }
+
+    var i18n = vnode.context.$i18n;
+    if (localeEqual(el, vnode) &&
+      (looseEqual(binding.value, binding.oldValue) &&
+       looseEqual(el._localeMessage, i18n.getLocaleMessage(i18n.locale)))) { return }
+
+    t(el, binding, vnode);
+  }
+
+  function unbind (el, binding, vnode, oldVNode) {
+    var vm = vnode.context;
+    if (!vm) {
+      warn('Vue instance does not exists in VNode context');
+      return
+    }
+
+    var i18n = vnode.context.$i18n || {};
+    if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
+      el.textContent = '';
+    }
+    el._vt = undefined;
+    delete el['_vt'];
+    el._locale = undefined;
+    delete el['_locale'];
+    el._localeMessage = undefined;
+    delete el['_localeMessage'];
+  }
+
+  function assert (el, vnode) {
+    var vm = vnode.context;
+    if (!vm) {
+      warn('Vue instance does not exists in VNode context');
+      return false
+    }
+
+    if (!vm.$i18n) {
+      warn('VueI18n instance does not exists in Vue instance');
+      return false
+    }
+
+    return true
+  }
+
+  function localeEqual (el, vnode) {
+    var vm = vnode.context;
+    return el._locale === vm.$i18n.locale
+  }
+
+  function t (el, binding, vnode) {
+    var ref$1, ref$2;
+
+    var value = binding.value;
+
+    var ref = parseValue(value);
+    var path = ref.path;
+    var locale = ref.locale;
+    var args = ref.args;
+    var choice = ref.choice;
+    if (!path && !locale && !args) {
+      warn('value type not supported');
+      return
+    }
+
+    if (!path) {
+      warn('`path` is required in v-t directive');
+      return
+    }
+
+    var vm = vnode.context;
+    if (choice != null) {
+      el._vt = el.textContent = (ref$1 = vm.$i18n).tc.apply(ref$1, [ path, choice ].concat( makeParams(locale, args) ));
+    } else {
+      el._vt = el.textContent = (ref$2 = vm.$i18n).t.apply(ref$2, [ path ].concat( makeParams(locale, args) ));
+    }
+    el._locale = vm.$i18n.locale;
+    el._localeMessage = vm.$i18n.getLocaleMessage(vm.$i18n.locale);
+  }
+
+  function parseValue (value) {
+    var path;
+    var locale;
+    var args;
+    var choice;
+
+    if (isString(value)) {
+      path = value;
+    } else if (isPlainObject(value)) {
+      path = value.path;
+      locale = value.locale;
+      args = value.args;
+      choice = value.choice;
+    }
+
+    return { path: path, locale: locale, args: args, choice: choice }
+  }
+
+  function makeParams (locale, args) {
+    var params = [];
+
+    locale && params.push(locale);
+    if (args && (Array.isArray(args) || isPlainObject(args))) {
+      params.push(args);
+    }
+
+    return params
+  }
+
+  var Vue;
+
+  function install (_Vue) {
+    /* istanbul ignore if */
+    if (install.installed && _Vue === Vue) {
+      warn('already installed.');
+      return
+    }
+    install.installed = true;
+
+    Vue = _Vue;
+
+    var version = (Vue.version && Number(Vue.version.split('.')[0])) || -1;
+    /* istanbul ignore if */
+    if (version < 2) {
+      warn(("vue-i18n (" + (install.version) + ") need to use Vue 2.0 or later (Vue: " + (Vue.version) + ")."));
+      return
+    }
+
+    extend(Vue);
+    Vue.mixin(mixin);
+    Vue.directive('t', { bind: bind, update: update, unbind: unbind });
+    Vue.component(interpolationComponent.name, interpolationComponent);
+    Vue.component(numberComponent.name, numberComponent);
+
+    // use simple mergeStrategies to prevent i18n instance lose '__proto__'
+    var strats = Vue.config.optionMergeStrategies;
+    strats.i18n = function (parentVal, childVal) {
+      return childVal === undefined
+        ? parentVal
+        : childVal
+    };
+  }
+
+  /*  */
+
+  var BaseFormatter = function BaseFormatter () {
+    this._caches = Object.create(null);
+  };
+
+  BaseFormatter.prototype.interpolate = function interpolate (message, values) {
+    if (!values) {
+      return [message]
+    }
+    var tokens = this._caches[message];
+    if (!tokens) {
+      tokens = parse(message);
+      this._caches[message] = tokens;
+    }
+    return compile(tokens, values)
+  };
+
+
+
+  var RE_TOKEN_LIST_VALUE = /^(?:\d)+/;
+  var RE_TOKEN_NAMED_VALUE = /^(?:\w)+/;
+
+  function parse (format) {
+    var tokens = [];
+    var position = 0;
+
+    var text = '';
+    while (position < format.length) {
+      var char = format[position++];
+      if (char === '{') {
+        if (text) {
+          tokens.push({ type: 'text', value: text });
+        }
+
+        text = '';
+        var sub = '';
+        char = format[position++];
+        while (char !== undefined && char !== '}') {
+          sub += char;
+          char = format[position++];
+        }
+        var isClosed = char === '}';
+
+        var type = RE_TOKEN_LIST_VALUE.test(sub)
+          ? 'list'
+          : isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
+            ? 'named'
+            : 'unknown';
+        tokens.push({ value: sub, type: type });
+      } else if (char === '%') {
+        // when found rails i18n syntax, skip text capture
+        if (format[(position)] !== '{') {
+          text += char;
+        }
+      } else {
+        text += char;
+      }
+    }
+
+    text && tokens.push({ type: 'text', value: text });
+
+    return tokens
+  }
+
+  function compile (tokens, values) {
+    var compiled = [];
+    var index = 0;
+
+    var mode = Array.isArray(values)
+      ? 'list'
+      : isObject(values)
+        ? 'named'
+        : 'unknown';
+    if (mode === 'unknown') { return compiled }
+
+    while (index < tokens.length) {
+      var token = tokens[index];
+      switch (token.type) {
+        case 'text':
+          compiled.push(token.value);
+          break
+        case 'list':
+          compiled.push(values[parseInt(token.value, 10)]);
+          break
+        case 'named':
+          if (mode === 'named') {
+            compiled.push((values)[token.value]);
+          } else {
+            {
+              warn(("Type of token '" + (token.type) + "' and format of value '" + mode + "' don't match!"));
+            }
+          }
+          break
+        case 'unknown':
+          {
+            warn("Detect 'unknown' type of token!");
+          }
+          break
+      }
+      index++;
+    }
+
+    return compiled
+  }
+
+  /*  */
+
+  /**
+   *  Path parser
+   *  - Inspired:
+   *    Vue.js Path parser
+   */
+
+  // actions
+  var APPEND = 0;
+  var PUSH = 1;
+  var INC_SUB_PATH_DEPTH = 2;
+  var PUSH_SUB_PATH = 3;
+
+  // states
+  var BEFORE_PATH = 0;
+  var IN_PATH = 1;
+  var BEFORE_IDENT = 2;
+  var IN_IDENT = 3;
+  var IN_SUB_PATH = 4;
+  var IN_SINGLE_QUOTE = 5;
+  var IN_DOUBLE_QUOTE = 6;
+  var AFTER_PATH = 7;
+  var ERROR = 8;
+
+  var pathStateMachine = [];
+
+  pathStateMachine[BEFORE_PATH] = {
+    'ws': [BEFORE_PATH],
+    'ident': [IN_IDENT, APPEND],
+    '[': [IN_SUB_PATH],
+    'eof': [AFTER_PATH]
+  };
+
+  pathStateMachine[IN_PATH] = {
+    'ws': [IN_PATH],
+    '.': [BEFORE_IDENT],
+    '[': [IN_SUB_PATH],
+    'eof': [AFTER_PATH]
+  };
+
+  pathStateMachine[BEFORE_IDENT] = {
+    'ws': [BEFORE_IDENT],
+    'ident': [IN_IDENT, APPEND],
+    '0': [IN_IDENT, APPEND],
+    'number': [IN_IDENT, APPEND]
+  };
+
+  pathStateMachine[IN_IDENT] = {
+    'ident': [IN_IDENT, APPEND],
+    '0': [IN_IDENT, APPEND],
+    'number': [IN_IDENT, APPEND],
+    'ws': [IN_PATH, PUSH],
+    '.': [BEFORE_IDENT, PUSH],
+    '[': [IN_SUB_PATH, PUSH],
+    'eof': [AFTER_PATH, PUSH]
+  };
+
+  pathStateMachine[IN_SUB_PATH] = {
+    "'": [IN_SINGLE_QUOTE, APPEND],
+    '"': [IN_DOUBLE_QUOTE, APPEND],
+    '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
+    ']': [IN_PATH, PUSH_SUB_PATH],
+    'eof': ERROR,
+    'else': [IN_SUB_PATH, APPEND]
+  };
+
+  pathStateMachine[IN_SINGLE_QUOTE] = {
+    "'": [IN_SUB_PATH, APPEND],
+    'eof': ERROR,
+    'else': [IN_SINGLE_QUOTE, APPEND]
+  };
+
+  pathStateMachine[IN_DOUBLE_QUOTE] = {
+    '"': [IN_SUB_PATH, APPEND],
+    'eof': ERROR,
+    'else': [IN_DOUBLE_QUOTE, APPEND]
+  };
+
+  /**
+   * Check if an expression is a literal value.
+   */
+
+  var literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
+  function isLiteral (exp) {
+    return literalValueRE.test(exp)
+  }
+
+  /**
+   * Strip quotes from a string
+   */
+
+  function stripQuotes (str) {
+    var a = str.charCodeAt(0);
+    var b = str.charCodeAt(str.length - 1);
+    return a === b && (a === 0x22 || a === 0x27)
+      ? str.slice(1, -1)
+      : str
+  }
+
+  /**
+   * Determine the type of a character in a keypath.
+   */
+
+  function getPathCharType (ch) {
+    if (ch === undefined || ch === null) { return 'eof' }
+
+    var code = ch.charCodeAt(0);
+
+    switch (code) {
+      case 0x5B: // [
+      case 0x5D: // ]
+      case 0x2E: // .
+      case 0x22: // "
+      case 0x27: // '
+        return ch
+
+      case 0x5F: // _
+      case 0x24: // $
+      case 0x2D: // -
+        return 'ident'
+
+      case 0x09: // Tab
+      case 0x0A: // Newline
+      case 0x0D: // Return
+      case 0xA0:  // No-break space
+      case 0xFEFF:  // Byte Order Mark
+      case 0x2028:  // Line Separator
+      case 0x2029:  // Paragraph Separator
+        return 'ws'
+    }
+
+    return 'ident'
+  }
+
+  /**
+   * Format a subPath, return its plain form if it is
+   * a literal string or number. Otherwise prepend the
+   * dynamic indicator (*).
+   */
+
+  function formatSubPath (path) {
+    var trimmed = path.trim();
+    // invalid leading 0
+    if (path.charAt(0) === '0' && isNaN(path)) { return false }
+
+    return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed
+  }
+
+  /**
+   * Parse a string path into an array of segments
+   */
+
+  function parse$1 (path) {
+    var keys = [];
+    var index = -1;
+    var mode = BEFORE_PATH;
+    var subPathDepth = 0;
+    var c;
+    var key;
+    var newChar;
+    var type;
+    var transition;
+    var action;
+    var typeMap;
+    var actions = [];
+
+    actions[PUSH] = function () {
+      if (key !== undefined) {
+        keys.push(key);
+        key = undefined;
+      }
+    };
+
+    actions[APPEND] = function () {
+      if (key === undefined) {
+        key = newChar;
+      } else {
+        key += newChar;
+      }
+    };
+
+    actions[INC_SUB_PATH_DEPTH] = function () {
+      actions[APPEND]();
+      subPathDepth++;
+    };
+
+    actions[PUSH_SUB_PATH] = function () {
+      if (subPathDepth > 0) {
+        subPathDepth--;
+        mode = IN_SUB_PATH;
+        actions[APPEND]();
+      } else {
+        subPathDepth = 0;
+        if (key === undefined) { return false }
+        key = formatSubPath(key);
+        if (key === false) {
+          return false
+        } else {
+          actions[PUSH]();
+        }
+      }
+    };
+
+    function maybeUnescapeQuote () {
+      var nextChar = path[index + 1];
+      if ((mode === IN_SINGLE_QUOTE && nextChar === "'") ||
+        (mode === IN_DOUBLE_QUOTE && nextChar === '"')) {
+        index++;
+        newChar = '\\' + nextChar;
+        actions[APPEND]();
+        return true
+      }
+    }
+
+    while (mode !== null) {
+      index++;
+      c = path[index];
+
+      if (c === '\\' && maybeUnescapeQuote()) {
+        continue
+      }
+
+      type = getPathCharType(c);
+      typeMap = pathStateMachine[mode];
+      transition = typeMap[type] || typeMap['else'] || ERROR;
+
+      if (transition === ERROR) {
+        return // parse error
+      }
+
+      mode = transition[0];
+      action = actions[transition[1]];
+      if (action) {
+        newChar = transition[2];
+        newChar = newChar === undefined
+          ? c
+          : newChar;
+        if (action() === false) {
+          return
+        }
+      }
+
+      if (mode === AFTER_PATH) {
+        return keys
+      }
+    }
+  }
+
+
+
+
+
+  var I18nPath = function I18nPath () {
+    this._cache = Object.create(null);
+  };
+
+  /**
+   * External parse that check for a cache hit first
+   */
+  I18nPath.prototype.parsePath = function parsePath (path) {
+    var hit = this._cache[path];
+    if (!hit) {
+      hit = parse$1(path);
+      if (hit) {
+        this._cache[path] = hit;
+      }
+    }
+    return hit || []
+  };
+
+  /**
+   * Get path value from path string
+   */
+  I18nPath.prototype.getPathValue = function getPathValue (obj, path) {
+    if (!isObject(obj)) { return null }
+
+    var paths = this.parsePath(path);
+    if (paths.length === 0) {
+      return null
+    } else {
+      var length = paths.length;
+      var last = obj;
+      var i = 0;
+      while (i < length) {
+        var value = last[paths[i]];
+        if (value === undefined) {
+          return null
+        }
+        last = value;
+        i++;
+      }
+
+      return last
+    }
+  };
+
+  /*  */
+
+
+
+  var htmlTagMatcher = /<\/?[\w\s="/.':;#-\/]+>/;
+  var linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
+  var linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/;
+  var bracketsMatcher = /[()]/g;
+  var defaultModifiers = {
+    'upper': function (str) { return str.toLocaleUpperCase(); },
+    'lower': function (str) { return str.toLocaleLowerCase(); },
+    'capitalize': function (str) { return ("" + (str.charAt(0).toLocaleUpperCase()) + (str.substr(1))); }
+  };
+
+  var defaultFormatter = new BaseFormatter();
+
+  var VueI18n = function VueI18n (options) {
+    var this$1 = this;
+    if ( options === void 0 ) options = {};
+
+    // Auto install if it is not done yet and `window` has `Vue`.
+    // To allow users to avoid auto-installation in some cases,
+    // this code should be placed here. See #290
+    /* istanbul ignore if */
+    if (!Vue && typeof window !== 'undefined' && window.Vue) {
+      install(window.Vue);
+    }
+
+    var locale = options.locale || 'en-US';
+    var fallbackLocale = options.fallbackLocale === false
+      ? false
+      : options.fallbackLocale || 'en-US';
+    var messages = options.messages || {};
+    var dateTimeFormats = options.dateTimeFormats || {};
+    var numberFormats = options.numberFormats || {};
+
+    this._vm = null;
+    this._formatter = options.formatter || defaultFormatter;
+    this._modifiers = options.modifiers || {};
+    this._missing = options.missing || null;
+    this._root = options.root || null;
+    this._sync = options.sync === undefined ? true : !!options.sync;
+    this._fallbackRoot = options.fallbackRoot === undefined
+      ? true
+      : !!options.fallbackRoot;
+    this._formatFallbackMessages = options.formatFallbackMessages === undefined
+      ? false
+      : !!options.formatFallbackMessages;
+    this._silentTranslationWarn = options.silentTranslationWarn === undefined
+      ? false
+      : options.silentTranslationWarn;
+    this._silentFallbackWarn = options.silentFallbackWarn === undefined
+      ? false
+      : !!options.silentFallbackWarn;
+    this._dateTimeFormatters = {};
+    this._numberFormatters = {};
+    this._path = new I18nPath();
+    this._dataListeners = [];
+    this._componentInstanceCreatedListener = options.componentInstanceCreatedListener || null;
+    this._preserveDirectiveContent = options.preserveDirectiveContent === undefined
+      ? false
+      : !!options.preserveDirectiveContent;
+    this.pluralizationRules = options.pluralizationRules || {};
+    this._warnHtmlInMessage = options.warnHtmlInMessage || 'off';
+    this._postTranslation = options.postTranslation || null;
+
+    /**
+     * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
+     * @param choicesLength {number} an overall amount of available choices
+     * @returns a final choice index
+    */
+    this.getChoiceIndex = function (choice, choicesLength) {
+      var thisPrototype = Object.getPrototypeOf(this$1);
+      if (thisPrototype && thisPrototype.getChoiceIndex) {
+        var prototypeGetChoiceIndex = (thisPrototype.getChoiceIndex);
+        return (prototypeGetChoiceIndex).call(this$1, choice, choicesLength)
+      }
+
+      // Default (old) getChoiceIndex implementation - english-compatible
+      var defaultImpl = function (_choice, _choicesLength) {
+        _choice = Math.abs(_choice);
+
+        if (_choicesLength === 2) {
+          return _choice
+            ? _choice > 1
+              ? 1
+              : 0
+            : 1
+        }
+
+        return _choice ? Math.min(_choice, 2) : 0
+      };
+
+      if (this$1.locale in this$1.pluralizationRules) {
+        return this$1.pluralizationRules[this$1.locale].apply(this$1, [choice, choicesLength])
+      } else {
+        return defaultImpl(choice, choicesLength)
+      }
+    };
+
+
+    this._exist = function (message, key) {
+      if (!message || !key) { return false }
+      if (!isNull(this$1._path.getPathValue(message, key))) { return true }
+      // fallback for flat key
+      if (message[key]) { return true }
+      return false
+    };
+
+    if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+      Object.keys(messages).forEach(function (locale) {
+        this$1._checkLocaleMessage(locale, this$1._warnHtmlInMessage, messages[locale]);
+      });
+    }
+
+    this._initVM({
+      locale: locale,
+      fallbackLocale: fallbackLocale,
+      messages: messages,
+      dateTimeFormats: dateTimeFormats,
+      numberFormats: numberFormats
+    });
+  };
+
+  var prototypeAccessors = { vm: { configurable: true },messages: { configurable: true },dateTimeFormats: { configurable: true },numberFormats: { configurable: true },availableLocales: { configurable: true },locale: { configurable: true },fallbackLocale: { configurable: true },formatFallbackMessages: { configurable: true },missing: { configurable: true },formatter: { configurable: true },silentTranslationWarn: { configurable: true },silentFallbackWarn: { configurable: true },preserveDirectiveContent: { configurable: true },warnHtmlInMessage: { configurable: true },postTranslation: { configurable: true } };
+
+  VueI18n.prototype._checkLocaleMessage = function _checkLocaleMessage (locale, level, message) {
+    var paths = [];
+
+    var fn = function (level, locale, message, paths) {
+      if (isPlainObject(message)) {
+        Object.keys(message).forEach(function (key) {
+          var val = message[key];
+          if (isPlainObject(val)) {
+            paths.push(key);
+            paths.push('.');
+            fn(level, locale, val, paths);
+            paths.pop();
+            paths.pop();
+          } else {
+            paths.push(key);
+            fn(level, locale, val, paths);
+            paths.pop();
+          }
+        });
+      } else if (isArray(message)) {
+        message.forEach(function (item, index) {
+          if (isPlainObject(item)) {
+            paths.push(("[" + index + "]"));
+            paths.push('.');
+            fn(level, locale, item, paths);
+            paths.pop();
+            paths.pop();
+          } else {
+            paths.push(("[" + index + "]"));
+            fn(level, locale, item, paths);
+            paths.pop();
+          }
+        });
+      } else if (isString(message)) {
+        var ret = htmlTagMatcher.test(message);
+        if (ret) {
+          var msg = "Detected HTML in message '" + message + "' of keypath '" + (paths.join('')) + "' at '" + locale + "'. Consider component interpolation with '<i18n>' to avoid XSS. See https://bit.ly/2ZqJzkp";
+          if (level === 'warn') {
+            warn(msg);
+          } else if (level === 'error') {
+            error(msg);
+          }
+        }
+      }
+    };
+
+    fn(level, locale, message, paths);
+  };
+
+  VueI18n.prototype._initVM = function _initVM (data) {
+    var silent = Vue.config.silent;
+    Vue.config.silent = true;
+    this._vm = new Vue({ data: data });
+    Vue.config.silent = silent;
+  };
+
+  VueI18n.prototype.destroyVM = function destroyVM () {
+    this._vm.$destroy();
+  };
+
+  VueI18n.prototype.subscribeDataChanging = function subscribeDataChanging (vm) {
+    this._dataListeners.push(vm);
+  };
+
+  VueI18n.prototype.unsubscribeDataChanging = function unsubscribeDataChanging (vm) {
+    remove(this._dataListeners, vm);
+  };
+
+  VueI18n.prototype.watchI18nData = function watchI18nData () {
+    var self = this;
+    return this._vm.$watch('$data', function () {
+      var i = self._dataListeners.length;
+      while (i--) {
+        Vue.nextTick(function () {
+          self._dataListeners[i] && self._dataListeners[i].$forceUpdate();
+        });
+      }
+    }, { deep: true })
+  };
+
+  VueI18n.prototype.watchLocale = function watchLocale () {
+    /* istanbul ignore if */
+    if (!this._sync || !this._root) { return null }
+    var target = this._vm;
+    return this._root.$i18n.vm.$watch('locale', function (val) {
+      target.$set(target, 'locale', val);
+      target.$forceUpdate();
+    }, { immediate: true })
+  };
+
+  VueI18n.prototype.onComponentInstanceCreated = function onComponentInstanceCreated (newI18n) {
+    if (this._componentInstanceCreatedListener) {
+      this._componentInstanceCreatedListener(newI18n, this);
+    }
+  };
+
+  prototypeAccessors.vm.get = function () { return this._vm };
+
+  prototypeAccessors.messages.get = function () { return looseClone(this._getMessages()) };
+  prototypeAccessors.dateTimeFormats.get = function () { return looseClone(this._getDateTimeFormats()) };
+  prototypeAccessors.numberFormats.get = function () { return looseClone(this._getNumberFormats()) };
+  prototypeAccessors.availableLocales.get = function () { return Object.keys(this.messages).sort() };
+
+  prototypeAccessors.locale.get = function () { return this._vm.locale };
+  prototypeAccessors.locale.set = function (locale) {
+    this._vm.$set(this._vm, 'locale', locale);
+  };
+
+  prototypeAccessors.fallbackLocale.get = function () { return this._vm.fallbackLocale };
+  prototypeAccessors.fallbackLocale.set = function (locale) {
+    this._localeChainCache = {};
+    this._vm.$set(this._vm, 'fallbackLocale', locale);
+  };
+
+  prototypeAccessors.formatFallbackMessages.get = function () { return this._formatFallbackMessages };
+  prototypeAccessors.formatFallbackMessages.set = function (fallback) { this._formatFallbackMessages = fallback; };
+
+  prototypeAccessors.missing.get = function () { return this._missing };
+  prototypeAccessors.missing.set = function (handler) { this._missing = handler; };
+
+  prototypeAccessors.formatter.get = function () { return this._formatter };
+  prototypeAccessors.formatter.set = function (formatter) { this._formatter = formatter; };
+
+  prototypeAccessors.silentTranslationWarn.get = function () { return this._silentTranslationWarn };
+  prototypeAccessors.silentTranslationWarn.set = function (silent) { this._silentTranslationWarn = silent; };
+
+  prototypeAccessors.silentFallbackWarn.get = function () { return this._silentFallbackWarn };
+  prototypeAccessors.silentFallbackWarn.set = function (silent) { this._silentFallbackWarn = silent; };
+
+  prototypeAccessors.preserveDirectiveContent.get = function () { return this._preserveDirectiveContent };
+  prototypeAccessors.preserveDirectiveContent.set = function (preserve) { this._preserveDirectiveContent = preserve; };
+
+  prototypeAccessors.warnHtmlInMessage.get = function () { return this._warnHtmlInMessage };
+  prototypeAccessors.warnHtmlInMessage.set = function (level) {
+      var this$1 = this;
+
+    var orgLevel = this._warnHtmlInMessage;
+    this._warnHtmlInMessage = level;
+    if (orgLevel !== level && (level === 'warn' || level === 'error')) {
+      var messages = this._getMessages();
+      Object.keys(messages).forEach(function (locale) {
+        this$1._checkLocaleMessage(locale, this$1._warnHtmlInMessage, messages[locale]);
+      });
+    }
+  };
+
+  prototypeAccessors.postTranslation.get = function () { return this._postTranslation };
+  prototypeAccessors.postTranslation.set = function (handler) { this._postTranslation = handler; };
+
+  VueI18n.prototype._getMessages = function _getMessages () { return this._vm.messages };
+  VueI18n.prototype._getDateTimeFormats = function _getDateTimeFormats () { return this._vm.dateTimeFormats };
+  VueI18n.prototype._getNumberFormats = function _getNumberFormats () { return this._vm.numberFormats };
+
+  VueI18n.prototype._warnDefault = function _warnDefault (locale, key, result, vm, values, interpolateMode) {
+    if (!isNull(result)) { return result }
+    if (this._missing) {
+      var missingRet = this._missing.apply(null, [locale, key, vm, values]);
+      if (isString(missingRet)) {
+        return missingRet
+      }
+    } else {
+      if (!this._isSilentTranslationWarn(key)) {
+        warn(
+          "Cannot translate the value of keypath '" + key + "'. " +
+          'Use the value of keypath as default.'
+        );
+      }
+    }
+
+    if (this._formatFallbackMessages) {
+      var parsedArgs = parseArgs.apply(void 0, values);
+      return this._render(key, interpolateMode, parsedArgs.params, key)
+    } else {
+      return key
+    }
+  };
+
+  VueI18n.prototype._isFallbackRoot = function _isFallbackRoot (val) {
+    return !val && !isNull(this._root) && this._fallbackRoot
+  };
+
+  VueI18n.prototype._isSilentFallbackWarn = function _isSilentFallbackWarn (key) {
+    return this._silentFallbackWarn instanceof RegExp
+      ? this._silentFallbackWarn.test(key)
+      : this._silentFallbackWarn
+  };
+
+  VueI18n.prototype._isSilentFallback = function _isSilentFallback (locale, key) {
+    return this._isSilentFallbackWarn(key) && (this._isFallbackRoot() || locale !== this.fallbackLocale)
+  };
+
+  VueI18n.prototype._isSilentTranslationWarn = function _isSilentTranslationWarn (key) {
+    return this._silentTranslationWarn instanceof RegExp
+      ? this._silentTranslationWarn.test(key)
+      : this._silentTranslationWarn
+  };
+
+  VueI18n.prototype._interpolate = function _interpolate (
+    locale,
+    message,
+    key,
+    host,
+    interpolateMode,
+    values,
+    visitedLinkStack
+  ) {
+    if (!message) { return null }
+
+    var pathRet = this._path.getPathValue(message, key);
+    if (isArray(pathRet) || isPlainObject(pathRet)) { return pathRet }
+
+    var ret;
+    if (isNull(pathRet)) {
+      /* istanbul ignore else */
+      if (isPlainObject(message)) {
+        ret = message[key];
+        if (!(isString(ret) || isFunction(ret))) {
+          if (!this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+            warn(("Value of key '" + key + "' is not a string or function !"));
+          }
+          return null
+        }
+      } else {
+        return null
+      }
+    } else {
+      /* istanbul ignore else */
+      if (isString(pathRet) || isFunction(pathRet)) {
+        ret = pathRet;
+      } else {
+        if (!this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+          warn(("Value of key '" + key + "' is not a string or function!"));
+        }
+        return null
+      }
+    }
+
+    // Check for the existence of links within the translated string
+    if (isString(ret) && (ret.indexOf('@:') >= 0 || ret.indexOf('@.') >= 0)) {
+      ret = this._link(locale, message, ret, host, 'raw', values, visitedLinkStack);
+    }
+
+    return this._render(ret, interpolateMode, values, key)
+  };
+
+  VueI18n.prototype._link = function _link (
+    locale,
+    message,
+    str,
+    host,
+    interpolateMode,
+    values,
+    visitedLinkStack
+  ) {
+    var ret = str;
+
+    // Match all the links within the local
+    // We are going to replace each of
+    // them with its translation
+    var matches = ret.match(linkKeyMatcher);
+    for (var idx in matches) {
+      // ie compatible: filter custom array
+      // prototype method
+      if (!matches.hasOwnProperty(idx)) {
+        continue
+      }
+      var link = matches[idx];
+      var linkKeyPrefixMatches = link.match(linkKeyPrefixMatcher);
+      var linkPrefix = linkKeyPrefixMatches[0];
+        var formatterName = linkKeyPrefixMatches[1];
+
+      // Remove the leading @:, @.case: and the brackets
+      var linkPlaceholder = link.replace(linkPrefix, '').replace(bracketsMatcher, '');
+
+      if (includes(visitedLinkStack, linkPlaceholder)) {
+        {
+          warn(("Circular reference found. \"" + link + "\" is already visited in the chain of " + (visitedLinkStack.reverse().join(' <- '))));
+        }
+        return ret
+      }
+      visitedLinkStack.push(linkPlaceholder);
+
+      // Translate the link
+      var translated = this._interpolate(
+        locale, message, linkPlaceholder, host,
+        interpolateMode === 'raw' ? 'string' : interpolateMode,
+        interpolateMode === 'raw' ? undefined : values,
+        visitedLinkStack
+      );
+
+      if (this._isFallbackRoot(translated)) {
+        if (!this._isSilentTranslationWarn(linkPlaceholder)) {
+          warn(("Fall back to translate the link placeholder '" + linkPlaceholder + "' with root locale."));
+        }
+        /* istanbul ignore if */
+        if (!this._root) { throw Error('unexpected error') }
+        var root = this._root.$i18n;
+        translated = root._translate(
+          root._getMessages(), root.locale, root.fallbackLocale,
+          linkPlaceholder, host, interpolateMode, values
+        );
+      }
+      translated = this._warnDefault(
+        locale, linkPlaceholder, translated, host,
+        isArray(values) ? values : [values],
+        interpolateMode
+      );
+
+      if (this._modifiers.hasOwnProperty(formatterName)) {
+        translated = this._modifiers[formatterName](translated);
+      } else if (defaultModifiers.hasOwnProperty(formatterName)) {
+        translated = defaultModifiers[formatterName](translated);
+      }
+
+      visitedLinkStack.pop();
+
+      // Replace the link with the translated
+      ret = !translated ? ret : ret.replace(link, translated);
+    }
+
+    return ret
+  };
+
+  VueI18n.prototype._createMessageContext = function _createMessageContext (values) {
+    var _list = isArray(values) ? values : [];
+    var _named = isObject(values) ? values : {};
+    var list = function (index) { return _list[index]; };
+    var named = function (key) { return _named[key]; };
+    return {
+      list: list,
+      named: named
+    }
+  };
+
+  VueI18n.prototype._render = function _render (message, interpolateMode, values, path) {
+    if (isFunction(message)) {
+      return message(this._createMessageContext(values))
+    }
+
+    var ret = this._formatter.interpolate(message, values, path);
+
+    // If the custom formatter refuses to work - apply the default one
+    if (!ret) {
+      ret = defaultFormatter.interpolate(message, values, path);
+    }
+
+    // if interpolateMode is **not** 'string' ('row'),
+    // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
+    return interpolateMode === 'string' && !isString(ret) ? ret.join('') : ret
+  };
+
+  VueI18n.prototype._appendItemToChain = function _appendItemToChain (chain, item, blocks) {
+    var follow = false;
+    if (!includes(chain, item)) {
+      follow = true;
+      if (item) {
+        follow = item[item.length - 1] !== '!';
+        item = item.replace(/!/g, '');
+        chain.push(item);
+        if (blocks && blocks[item]) {
+          follow = blocks[item];
+        }
+      }
+    }
+    return follow
+  };
+
+  VueI18n.prototype._appendLocaleToChain = function _appendLocaleToChain (chain, locale, blocks) {
+    var follow;
+    var tokens = locale.split('-');
+    do {
+      var item = tokens.join('-');
+      follow = this._appendItemToChain(chain, item, blocks);
+      tokens.splice(-1, 1);
+    } while (tokens.length && (follow === true))
+    return follow
+  };
+
+  VueI18n.prototype._appendBlockToChain = function _appendBlockToChain (chain, block, blocks) {
+    var follow = true;
+    for (var i = 0; (i < block.length) && (isBoolean(follow)); i++) {
+      var locale = block[i];
+      if (isString(locale)) {
+        follow = this._appendLocaleToChain(chain, locale, blocks);
+      }
+    }
+    return follow
+  };
+
+  VueI18n.prototype._getLocaleChain = function _getLocaleChain (start, fallbackLocale) {
+    if (start === '') { return [] }
+
+    if (!this._localeChainCache) {
+      this._localeChainCache = {};
+    }
+
+    var chain = this._localeChainCache[start];
+    if (!chain) {
+      if (!fallbackLocale) {
+        fallbackLocale = this.fallbackLocale;
+      }
+      chain = [];
+
+      // first block defined by start
+      var block = [start];
+
+      // while any intervening block found
+      while (isArray(block)) {
+        block = this._appendBlockToChain(
+          chain,
+          block,
+          fallbackLocale
+        );
+      }
+
+      // last block defined by default
+      var defaults;
+      if (isArray(fallbackLocale)) {
+        defaults = fallbackLocale;
+      } else if (isObject(fallbackLocale)) {
+        /* $FlowFixMe */
+        if (fallbackLocale['default']) {
+          defaults = fallbackLocale['default'];
+        } else {
+          defaults = null;
+        }
+      } else {
+        defaults = fallbackLocale;
+      }
+
+      // convert defaults to array
+      if (isString(defaults)) {
+        block = [defaults];
+      } else {
+        block = defaults;
+      }
+      if (block) {
+        this._appendBlockToChain(
+          chain,
+          block,
+          null
+        );
+      }
+      this._localeChainCache[start] = chain;
+    }
+    return chain
+  };
+
+  VueI18n.prototype._translate = function _translate (
+    messages,
+    locale,
+    fallback,
+    key,
+    host,
+    interpolateMode,
+    args
+  ) {
+    var chain = this._getLocaleChain(locale, fallback);
+    var res;
+    for (var i = 0; i < chain.length; i++) {
+      var step = chain[i];
+      res =
+        this._interpolate(step, messages[step], key, host, interpolateMode, args, [key]);
+      if (!isNull(res)) {
+        if (step !== locale && "development" !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+          warn(("Fall back to translate the keypath '" + key + "' with '" + step + "' locale."));
+        }
+        return res
+      }
+    }
+    return null
+  };
+
+  VueI18n.prototype._t = function _t (key, _locale, messages, host) {
+      var ref;
+
+      var values = [], len = arguments.length - 4;
+      while ( len-- > 0 ) values[ len ] = arguments[ len + 4 ];
+    if (!key) { return '' }
+
+    var parsedArgs = parseArgs.apply(void 0, values);
+    var locale = parsedArgs.locale || _locale;
+
+    var ret = this._translate(
+      messages, locale, this.fallbackLocale, key,
+      host, 'string', parsedArgs.params
+    );
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(("Fall back to translate the keypath '" + key + "' with root locale."));
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return (ref = this._root).$t.apply(ref, [ key ].concat( values ))
+    } else {
+      ret = this._warnDefault(locale, key, ret, host, values, 'string');
+      if (this._postTranslation && ret !== null && ret !== undefined) {
+        ret = this._postTranslation(ret, key);
+      }
+      return ret
+    }
+  };
+
+  VueI18n.prototype.t = function t (key) {
+      var ref;
+
+      var values = [], len = arguments.length - 1;
+      while ( len-- > 0 ) values[ len ] = arguments[ len + 1 ];
+    return (ref = this)._t.apply(ref, [ key, this.locale, this._getMessages(), null ].concat( values ))
+  };
+
+  VueI18n.prototype._i = function _i (key, locale, messages, host, values) {
+    var ret =
+      this._translate(messages, locale, this.fallbackLocale, key, host, 'raw', values);
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key)) {
+        warn(("Fall back to interpolate the keypath '" + key + "' with root locale."));
+      }
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n.i(key, locale, values)
+    } else {
+      return this._warnDefault(locale, key, ret, host, [values], 'raw')
+    }
+  };
+
+  VueI18n.prototype.i = function i (key, locale, values) {
+    /* istanbul ignore if */
+    if (!key) { return '' }
+
+    if (!isString(locale)) {
+      locale = this.locale;
+    }
+
+    return this._i(key, locale, this._getMessages(), null, values)
+  };
+
+  VueI18n.prototype._tc = function _tc (
+    key,
+    _locale,
+    messages,
+    host,
+    choice
+  ) {
+      var ref;
+
+      var values = [], len = arguments.length - 5;
+      while ( len-- > 0 ) values[ len ] = arguments[ len + 5 ];
+    if (!key) { return '' }
+    if (choice === undefined) {
+      choice = 1;
+    }
+
+    var predefined = { 'count': choice, 'n': choice };
+    var parsedArgs = parseArgs.apply(void 0, values);
+    parsedArgs.params = Object.assign(predefined, parsedArgs.params);
+    values = parsedArgs.locale === null ? [parsedArgs.params] : [parsedArgs.locale, parsedArgs.params];
+    return this.fetchChoice((ref = this)._t.apply(ref, [ key, _locale, messages, host ].concat( values )), choice)
+  };
+
+  VueI18n.prototype.fetchChoice = function fetchChoice (message, choice) {
+    /* istanbul ignore if */
+    if (!message && !isString(message)) { return null }
+    var choices = message.split('|');
+
+    choice = this.getChoiceIndex(choice, choices.length);
+    if (!choices[choice]) { return message }
+    return choices[choice].trim()
+  };
+
+  VueI18n.prototype.tc = function tc (key, choice) {
+      var ref;
+
+      var values = [], len = arguments.length - 2;
+      while ( len-- > 0 ) values[ len ] = arguments[ len + 2 ];
+    return (ref = this)._tc.apply(ref, [ key, this.locale, this._getMessages(), null, choice ].concat( values ))
+  };
+
+  VueI18n.prototype._te = function _te (key, locale, messages) {
+      var args = [], len = arguments.length - 3;
+      while ( len-- > 0 ) args[ len ] = arguments[ len + 3 ];
+
+    var _locale = parseArgs.apply(void 0, args).locale || locale;
+    return this._exist(messages[_locale], key)
+  };
+
+  VueI18n.prototype.te = function te (key, locale) {
+    return this._te(key, this.locale, this._getMessages(), locale)
+  };
+
+  VueI18n.prototype.getLocaleMessage = function getLocaleMessage (locale) {
+    return looseClone(this._vm.messages[locale] || {})
+  };
+
+  VueI18n.prototype.setLocaleMessage = function setLocaleMessage (locale, message) {
+    if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+      this._checkLocaleMessage(locale, this._warnHtmlInMessage, message);
+    }
+    this._vm.$set(this._vm.messages, locale, message);
+  };
+
+  VueI18n.prototype.mergeLocaleMessage = function mergeLocaleMessage (locale, message) {
+    if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+      this._checkLocaleMessage(locale, this._warnHtmlInMessage, message);
+    }
+    this._vm.$set(this._vm.messages, locale, merge({}, this._vm.messages[locale] || {}, message));
+  };
+
+  VueI18n.prototype.getDateTimeFormat = function getDateTimeFormat (locale) {
+    return looseClone(this._vm.dateTimeFormats[locale] || {})
+  };
+
+  VueI18n.prototype.setDateTimeFormat = function setDateTimeFormat (locale, format) {
+    this._vm.$set(this._vm.dateTimeFormats, locale, format);
+    this._clearDateTimeFormat(locale, format);
+  };
+
+  VueI18n.prototype.mergeDateTimeFormat = function mergeDateTimeFormat (locale, format) {
+    this._vm.$set(this._vm.dateTimeFormats, locale, merge(this._vm.dateTimeFormats[locale] || {}, format));
+    this._clearDateTimeFormat(locale, format);
+  };
+
+  VueI18n.prototype._clearDateTimeFormat = function _clearDateTimeFormat (locale, format) {
+    for (var key in format) {
+      var id = locale + "__" + key;
+
+      if (!this._dateTimeFormatters.hasOwnProperty(id)) {
+        continue
+      }
+
+      delete this._dateTimeFormatters[id];
+    }
+  };
+
+  VueI18n.prototype._localizeDateTime = function _localizeDateTime (
+    value,
+    locale,
+    fallback,
+    dateTimeFormats,
+    key
+  ) {
+    var _locale = locale;
+    var formats = dateTimeFormats[_locale];
+
+    var chain = this._getLocaleChain(locale, fallback);
+    for (var i = 0; i < chain.length; i++) {
+      var current = _locale;
+      var step = chain[i];
+      formats = dateTimeFormats[step];
+      _locale = step;
+      // fallback locale
+      if (isNull(formats) || isNull(formats[key])) {
+        if (step !== locale && "development" !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+          warn(("Fall back to '" + step + "' datetime formats from '" + current + "' datetime formats."));
+        }
+      } else {
+        break
+      }
+    }
+
+    if (isNull(formats) || isNull(formats[key])) {
+      return null
+    } else {
+      var format = formats[key];
+      var id = _locale + "__" + key;
+      var formatter = this._dateTimeFormatters[id];
+      if (!formatter) {
+        formatter = this._dateTimeFormatters[id] = new Intl.DateTimeFormat(_locale, format);
+      }
+      return formatter.format(value)
+    }
+  };
+
+  VueI18n.prototype._d = function _d (value, locale, key) {
+    /* istanbul ignore if */
+    if (!VueI18n.availabilities.dateTimeFormat) {
+      warn('Cannot format a Date value due to not supported Intl.DateTimeFormat.');
+      return ''
+    }
+
+    if (!key) {
+      return new Intl.DateTimeFormat(locale).format(value)
+    }
+
+    var ret =
+      this._localizeDateTime(value, locale, this.fallbackLocale, this._getDateTimeFormats(), key);
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(("Fall back to datetime localization of root: key '" + key + "'."));
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n.d(value, key, locale)
+    } else {
+      return ret || ''
+    }
+  };
+
+  VueI18n.prototype.d = function d (value) {
+      var args = [], len = arguments.length - 1;
+      while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+
+    var locale = this.locale;
+    var key = null;
+
+    if (args.length === 1) {
+      if (isString(args[0])) {
+        key = args[0];
+      } else if (isObject(args[0])) {
+        if (args[0].locale) {
+          locale = args[0].locale;
+        }
+        if (args[0].key) {
+          key = args[0].key;
+        }
+      }
+    } else if (args.length === 2) {
+      if (isString(args[0])) {
+        key = args[0];
+      }
+      if (isString(args[1])) {
+        locale = args[1];
+      }
+    }
+
+    return this._d(value, locale, key)
+  };
+
+  VueI18n.prototype.getNumberFormat = function getNumberFormat (locale) {
+    return looseClone(this._vm.numberFormats[locale] || {})
+  };
+
+  VueI18n.prototype.setNumberFormat = function setNumberFormat (locale, format) {
+    this._vm.$set(this._vm.numberFormats, locale, format);
+    this._clearNumberFormat(locale, format);
+  };
+
+  VueI18n.prototype.mergeNumberFormat = function mergeNumberFormat (locale, format) {
+    this._vm.$set(this._vm.numberFormats, locale, merge(this._vm.numberFormats[locale] || {}, format));
+    this._clearNumberFormat(locale, format);
+  };
+
+  VueI18n.prototype._clearNumberFormat = function _clearNumberFormat (locale, format) {
+    for (var key in format) {
+      var id = locale + "__" + key;
+
+      if (!this._numberFormatters.hasOwnProperty(id)) {
+        continue
+      }
+
+      delete this._numberFormatters[id];
+    }
+  };
+
+  VueI18n.prototype._getNumberFormatter = function _getNumberFormatter (
+    value,
+    locale,
+    fallback,
+    numberFormats,
+    key,
+    options
+  ) {
+    var _locale = locale;
+    var formats = numberFormats[_locale];
+
+    var chain = this._getLocaleChain(locale, fallback);
+    for (var i = 0; i < chain.length; i++) {
+      var current = _locale;
+      var step = chain[i];
+      formats = numberFormats[step];
+      _locale = step;
+      // fallback locale
+      if (isNull(formats) || isNull(formats[key])) {
+        if (step !== locale && "development" !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+          warn(("Fall back to '" + step + "' number formats from '" + current + "' number formats."));
+        }
+      } else {
+        break
+      }
+    }
+
+    if (isNull(formats) || isNull(formats[key])) {
+      return null
+    } else {
+      var format = formats[key];
+
+      var formatter;
+      if (options) {
+        // If options specified - create one time number formatter
+        formatter = new Intl.NumberFormat(_locale, Object.assign({}, format, options));
+      } else {
+        var id = _locale + "__" + key;
+        formatter = this._numberFormatters[id];
+        if (!formatter) {
+          formatter = this._numberFormatters[id] = new Intl.NumberFormat(_locale, format);
+        }
+      }
+      return formatter
+    }
+  };
+
+  VueI18n.prototype._n = function _n (value, locale, key, options) {
+    /* istanbul ignore if */
+    if (!VueI18n.availabilities.numberFormat) {
+      {
+        warn('Cannot format a Number value due to not supported Intl.NumberFormat.');
+      }
+      return ''
+    }
+
+    if (!key) {
+      var nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options);
+      return nf.format(value)
+    }
+
+    var formatter = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
+    var ret = formatter && formatter.format(value);
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(("Fall back to number localization of root: key '" + key + "'."));
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n.n(value, Object.assign({}, { key: key, locale: locale }, options))
+    } else {
+      return ret || ''
+    }
+  };
+
+  VueI18n.prototype.n = function n (value) {
+      var args = [], len = arguments.length - 1;
+      while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
+
+    var locale = this.locale;
+    var key = null;
+    var options = null;
+
+    if (args.length === 1) {
+      if (isString(args[0])) {
+        key = args[0];
+      } else if (isObject(args[0])) {
+        if (args[0].locale) {
+          locale = args[0].locale;
+        }
+        if (args[0].key) {
+          key = args[0].key;
+        }
+
+        // Filter out number format options only
+        options = Object.keys(args[0]).reduce(function (acc, key) {
+            var obj;
+
+          if (includes(numberFormatKeys, key)) {
+            return Object.assign({}, acc, ( obj = {}, obj[key] = args[0][key], obj ))
+          }
+          return acc
+        }, null);
+      }
+    } else if (args.length === 2) {
+      if (isString(args[0])) {
+        key = args[0];
+      }
+      if (isString(args[1])) {
+        locale = args[1];
+      }
+    }
+
+    return this._n(value, locale, key, options)
+  };
+
+  VueI18n.prototype._ntp = function _ntp (value, locale, key, options) {
+    /* istanbul ignore if */
+    if (!VueI18n.availabilities.numberFormat) {
+      {
+        warn('Cannot format to parts a Number value due to not supported Intl.NumberFormat.');
+      }
+      return []
+    }
+
+    if (!key) {
+      var nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options);
+      return nf.formatToParts(value)
+    }
+
+    var formatter = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
+    var ret = formatter && formatter.formatToParts(value);
+    if (this._isFallbackRoot(ret)) {
+      if (!this._isSilentTranslationWarn(key)) {
+        warn(("Fall back to format number to parts of root: key '" + key + "' ."));
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n._ntp(value, locale, key, options)
+    } else {
+      return ret || []
+    }
+  };
+
+  Object.defineProperties( VueI18n.prototype, prototypeAccessors );
+
+  var availabilities;
+  // $FlowFixMe
+  Object.defineProperty(VueI18n, 'availabilities', {
+    get: function get () {
+      if (!availabilities) {
+        var intlDefined = typeof Intl !== 'undefined';
+        availabilities = {
+          dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
+          numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
+        };
+      }
+
+      return availabilities
+    }
+  });
+
+  VueI18n.install = install;
+  VueI18n.version = '8.21.0';
+
+  return VueI18n;
+
+})));

File diff suppressed because it is too large
+ 5 - 0
plugin/vue-i18n/dist/vue-i18n.min.js


+ 176 - 0
plugin/vue-i18n/package.json

@@ -0,0 +1,176 @@
+{
+  "_args": [
+    [
+      "vue-i18n@8.21.0",
+      "D:\\2023\\4\\wwbsr"
+    ]
+  ],
+  "_from": "vue-i18n@8.21.0",
+  "_id": "vue-i18n@8.21.0",
+  "_inBundle": false,
+  "_integrity": "sha1-UmRQUl/buch3aFtbpsuVc7c9OUA=",
+  "_location": "/vue-i18n",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "vue-i18n@8.21.0",
+    "name": "vue-i18n",
+    "escapedName": "vue-i18n",
+    "rawSpec": "8.21.0",
+    "saveSpec": null,
+    "fetchSpec": "8.21.0"
+  },
+  "_requiredBy": [
+    "/"
+  ],
+  "_resolved": "https://registry.npm.taobao.org/vue-i18n/download/vue-i18n-8.21.0.tgz?cache=0&sync_timestamp=1597336528269&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-i18n%2Fdownload%2Fvue-i18n-8.21.0.tgz",
+  "_spec": "8.21.0",
+  "_where": "D:\\2023\\4\\wwbsr",
+  "author": {
+    "name": "kazuya kawaguchi",
+    "email": "kawakazu80@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/kazupon/vue-i18n/issues"
+  },
+  "changelog": {
+    "labels": {
+      "Type: Feature": ":star: New Features",
+      "Type: Bug": ":bug: Bug Fixes",
+      "Type: Security": ":lock: Security Fixes",
+      "Type: Performance": ":chart_with_upwards_trend: Performance Fixes",
+      "Type: Improvement": ":zap: Improved Features",
+      "Type: Breaking": ":boom: Breaking Change",
+      "Type: Deprecated": ":warning: Deprecated Features",
+      "Type: I18n": ":globe_with_meridians: Internationalization",
+      "Type: A11y": ":wheelchair: Accessibility",
+      "Type: Documentation": ":pencil: Documentation"
+    }
+  },
+  "description": "Internationalization plugin for Vue.js",
+  "devDependencies": {
+    "@babel/core": "^7.1.0",
+    "@babel/plugin-proposal-class-properties": "^7.1.0",
+    "@babel/plugin-syntax-flow": "^7.0.0",
+    "@babel/plugin-transform-flow-strip-types": "^7.0.0",
+    "@typescript-eslint/eslint-plugin": "^3.0.0",
+    "@typescript-eslint/parser": "^3.0.0",
+    "@vue/babel-preset-app": "^4.4.1",
+    "babel-eslint": "^10.1.0",
+    "babel-loader": "^8.1.0",
+    "babel-plugin-istanbul": "^6.0.0",
+    "babel-preset-power-assert": "^3.0.0",
+    "buble": "^0.19.3",
+    "chromedriver": "^83.0.0",
+    "core-js": "^3.6.5",
+    "cross-env": "^7.0.2",
+    "cross-spawn": "^7.0.3",
+    "eslint": "^6.8.0",
+    "eslint-loader": "^4.0.2",
+    "eslint-plugin-flowtype": "^4.7.0",
+    "eslint-plugin-ie11": "^1.0.0",
+    "eslint-plugin-no-autofix": "^1.0.1",
+    "eslint-plugin-vue": "^6.2.2",
+    "eslint-plugin-vue-libs": "^4.0.0",
+    "flow-bin": "^0.38.0",
+    "http-server": "^0.12.3",
+    "intl": "^1.2.5",
+    "karma": "^5.0.9",
+    "karma-chrome-launcher": "^3.1.0",
+    "karma-coverage": "^2.0.2",
+    "karma-firefox-launcher": "^1.1.0",
+    "karma-mocha": "^2.0.1",
+    "karma-mocha-reporter": "^2.2.5",
+    "karma-safari-launcher": "^1.0.0",
+    "karma-sauce-launcher": "^4.1.5",
+    "karma-sourcemap-loader": "^0.3.7",
+    "karma-webpack": "^4.0.2",
+    "lerna-changelog": "^1.0.0",
+    "lerna-changelog-label-schema": "^3.0.0",
+    "mocha": "^7.2.0",
+    "mocha-loader": "^5.0.0",
+    "nightwatch": "^1.3.5",
+    "nightwatch-helpers": "^1.2.0",
+    "power-assert": "^1.6.0",
+    "rollup": "^0.66.0",
+    "rollup-plugin-buble": "^0.19.2",
+    "rollup-plugin-commonjs": "^9.1.8",
+    "rollup-plugin-flow-no-whitespace": "^1.0.0",
+    "rollup-plugin-node-resolve": "^3.4.0",
+    "rollup-plugin-replace": "^2.0.0",
+    "selenium-server": "^3.141.59",
+    "shipjs": "^0.17.0",
+    "sinon": "^9.0.2",
+    "terser": "^3.17.0",
+    "typescript": "^3.9.3",
+    "vue": "^2.5.17",
+    "vue-github-button": "^1.1.2",
+    "vue-template-compiler": "^2.5.17",
+    "vuepress": "^1.5.0",
+    "webpack": "^4.43.0",
+    "webpack-cli": "^3.1.1",
+    "webpack-dev-middleware": "^3.7.2",
+    "webpack-dev-server": "^3.11.0"
+  },
+  "files": [
+    "dist/vue-i18n.js",
+    "dist/vue-i18n.min.js",
+    "dist/vue-i18n.common.js",
+    "dist/vue-i18n.esm.js",
+    "dist/vue-i18n.esm.browser.js",
+    "dist/vue-i18n.esm.browser.min.js",
+    "src/**/*.js",
+    "types/*.d.ts",
+    "decls",
+    "vetur/tags.json",
+    "vetur/attributes.json"
+  ],
+  "homepage": "https://github.com/kazupon/vue-i18n#readme",
+  "keywords": [
+    "i18n",
+    "internationalization",
+    "plugin",
+    "vue",
+    "vue.js"
+  ],
+  "license": "MIT",
+  "main": "dist/vue-i18n.common.js",
+  "module": "dist/vue-i18n.esm.js",
+  "name": "vue-i18n",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/kazupon/vue-i18n.git"
+  },
+  "scripts": {
+    "build": "node config/build.js",
+    "clean": "rm -rf coverage && rm -rf dist/*.js* && rm ./*.log",
+    "coverage": "cat ./coverage/lcov.info",
+    "dev": "cross-env BABEL_ENV=test webpack-dev-server --inline --hot --open --content-base ./test/unit/ --config config/webpack.dev.conf.js",
+    "docs:build": "cross-env NODE_ENV=production node config/version.js && cross-env NODE_ENV=production vuepress build vuepress -d docs",
+    "docs:clean": "rm -rf docs/**",
+    "docs:dev": "vuepress dev vuepress",
+    "flow": "flow check",
+    "lint": "eslint --fix src test types/**/*.ts",
+    "release:prepare": "shipjs prepare",
+    "release:trigger": "shipjs trigger",
+    "sauce": "npm run sauce:coolkids && npm run sauce:ie && npm run sauce:mobile",
+    "sauce:coolkids": "karma start config/karma.sauce.conf.js -- 0",
+    "sauce:ie": "karma start config/karma.sauce.conf.js -- 1",
+    "sauce:mobile": "karma start config/karma.sauce.conf.js -- 2",
+    "test": "npm run lint && npm run flow && npm run test:types && npm run test:cover && npm run test:e2e",
+    "test:cover": "cross-env BABEL_ENV=test karma start config/karma.cover.conf.js",
+    "test:e2e": "npm run build && node test/e2e/runner.js",
+    "test:types": "tsc -p types",
+    "test:unit": "cross-env BABEL_ENV=test karma start config/karma.unit.conf.js",
+    "test:unit:ci": "cross-env BABEL_ENV=test karma start config/karma.unit.ci.conf.js"
+  },
+  "sideEffects": false,
+  "types": "types/index.d.ts",
+  "unpkg": "dist/vue-i18n.js",
+  "version": "8.21.0",
+  "vetur": {
+    "tags": "vetur/tags.json",
+    "attributes": "vetur/attributes.json"
+  }
+}

+ 101 - 0
plugin/vue-i18n/src/components/interpolation.js

@@ -0,0 +1,101 @@
+/* @flow */
+
+import { warn } from '../util'
+
+export default {
+  name: 'i18n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    path: {
+      type: String,
+      required: true
+    },
+    locale: {
+      type: String
+    },
+    places: {
+      type: [Array, Object]
+    }
+  },
+  render (h: Function, { data, parent, props, slots }: Object) {
+    const { $i18n } = parent
+    if (!$i18n) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot find VueI18n instance!')
+      }
+      return
+    }
+
+    const { path, locale, places } = props
+    const params = slots()
+    const children = $i18n.i(
+      path,
+      locale,
+      onlyHasDefaultPlace(params) || places
+        ? useLegacyPlaces(params.default, places)
+        : params
+    )
+
+    const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
+    return tag ? h(tag, data, children) : children
+  }
+}
+
+function onlyHasDefaultPlace (params) {
+  let prop
+  for (prop in params) {
+    if (prop !== 'default') { return false }
+  }
+  return Boolean(prop)
+}
+
+function useLegacyPlaces (children, places) {
+  const params = places ? createParamsFromPlaces(places) : {}
+
+  if (!children) { return params }
+
+  // Filter empty text nodes
+  children = children.filter(child => {
+    return child.tag || child.text.trim() !== ''
+  })
+
+  const everyPlace = children.every(vnodeHasPlaceAttribute)
+  if (process.env.NODE_ENV !== 'production' && everyPlace) {
+    warn('`place` attribute is deprecated in next major version. Please switch to Vue slots.')
+  }
+
+  return children.reduce(
+    everyPlace ? assignChildPlace : assignChildIndex,
+    params
+  )
+}
+
+function createParamsFromPlaces (places) {
+  if (process.env.NODE_ENV !== 'production') {
+    warn('`places` prop is deprecated in next major version. Please switch to Vue slots.')
+  }
+
+  return Array.isArray(places)
+    ? places.reduce(assignChildIndex, {})
+    : Object.assign({}, places)
+}
+
+function assignChildPlace (params, child) {
+  if (child.data && child.data.attrs && child.data.attrs.place) {
+    params[child.data.attrs.place] = child
+  }
+  return params
+}
+
+function assignChildIndex (params, child, index) {
+  params[index] = child
+  return params
+}
+
+function vnodeHasPlaceAttribute (vnode) {
+  return Boolean(vnode.data && vnode.data.attrs && vnode.data.attrs.place)
+}

+ 70 - 0
plugin/vue-i18n/src/components/number.js

@@ -0,0 +1,70 @@
+/* @flow */
+
+import { warn, isString, isObject, includes, numberFormatKeys } from '../util'
+
+export default {
+  name: 'i18n-n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    value: {
+      type: Number,
+      required: true
+    },
+    format: {
+      type: [String, Object]
+    },
+    locale: {
+      type: String
+    }
+  },
+  render (h: Function, { props, parent, data }: Object) {
+    const i18n = parent.$i18n
+
+    if (!i18n) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot find VueI18n instance!')
+      }
+      return null
+    }
+
+    let key: ?string = null
+    let options: ?NumberFormatOptions = null
+
+    if (isString(props.format)) {
+      key = props.format
+    } else if (isObject(props.format)) {
+      if (props.format.key) {
+        key = props.format.key
+      }
+
+      // Filter out number format options only
+      options = Object.keys(props.format).reduce((acc, prop) => {
+        if (includes(numberFormatKeys, prop)) {
+          return Object.assign({}, acc, { [prop]: props.format[prop] })
+        }
+        return acc
+      }, null)
+    }
+
+    const locale: Locale = props.locale || i18n.locale
+    const parts: NumberFormatToPartsResult = i18n._ntp(props.value, locale, key, options)
+
+    const values = parts.map((part, index) => {
+      const slot: ?Function = data.scopedSlots && data.scopedSlots[part.type]
+      return slot ? slot({ [part.type]: part.value, index, parts }) : part.value
+    })
+
+    const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
+    return tag
+      ? h(tag, {
+        attrs: data.attrs,
+        'class': data['class'],
+        staticClass: data.staticClass
+      }, values)
+      : values
+  }
+}

+ 112 - 0
plugin/vue-i18n/src/directive.js

@@ -0,0 +1,112 @@
+/* @flow */
+
+import { warn, isString, isPlainObject, looseEqual } from './util'
+
+export function bind (el: any, binding: Object, vnode: any): void {
+  if (!assert(el, vnode)) { return }
+
+  t(el, binding, vnode)
+}
+
+export function update (el: any, binding: Object, vnode: any, oldVNode: any): void {
+  if (!assert(el, vnode)) { return }
+
+  const i18n: any = vnode.context.$i18n
+  if (localeEqual(el, vnode) &&
+    (looseEqual(binding.value, binding.oldValue) &&
+     looseEqual(el._localeMessage, i18n.getLocaleMessage(i18n.locale)))) { return }
+
+  t(el, binding, vnode)
+}
+
+export function unbind (el: any, binding: Object, vnode: any, oldVNode: any): void {
+  const vm: any = vnode.context
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context')
+    return
+  }
+
+  const i18n: any = vnode.context.$i18n || {}
+  if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
+    el.textContent = ''
+  }
+  el._vt = undefined
+  delete el['_vt']
+  el._locale = undefined
+  delete el['_locale']
+  el._localeMessage = undefined
+  delete el['_localeMessage']
+}
+
+function assert (el: any, vnode: any): boolean {
+  const vm: any = vnode.context
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context')
+    return false
+  }
+
+  if (!vm.$i18n) {
+    warn('VueI18n instance does not exists in Vue instance')
+    return false
+  }
+
+  return true
+}
+
+function localeEqual (el: any, vnode: any): boolean {
+  const vm: any = vnode.context
+  return el._locale === vm.$i18n.locale
+}
+
+function t (el: any, binding: Object, vnode: any): void {
+  const value: any = binding.value
+
+  const { path, locale, args, choice } = parseValue(value)
+  if (!path && !locale && !args) {
+    warn('value type not supported')
+    return
+  }
+
+  if (!path) {
+    warn('`path` is required in v-t directive')
+    return
+  }
+
+  const vm: any = vnode.context
+  if (choice != null) {
+    el._vt = el.textContent = vm.$i18n.tc(path, choice, ...makeParams(locale, args))
+  } else {
+    el._vt = el.textContent = vm.$i18n.t(path, ...makeParams(locale, args))
+  }
+  el._locale = vm.$i18n.locale
+  el._localeMessage = vm.$i18n.getLocaleMessage(vm.$i18n.locale)
+}
+
+function parseValue (value: any): Object {
+  let path: ?string
+  let locale: ?Locale
+  let args: any
+  let choice: ?number
+
+  if (isString(value)) {
+    path = value
+  } else if (isPlainObject(value)) {
+    path = value.path
+    locale = value.locale
+    args = value.args
+    choice = value.choice
+  }
+
+  return { path, locale, args, choice }
+}
+
+function makeParams (locale: Locale, args: any): Array<any> {
+  const params: Array<any> = []
+
+  locale && params.push(locale)
+  if (args && (Array.isArray(args) || isPlainObject(args))) {
+    params.push(args)
+  }
+
+  return params
+}

+ 33 - 0
plugin/vue-i18n/src/extend.js

@@ -0,0 +1,33 @@
+/* @flow */
+
+export default function extend (Vue: any): void {
+  if (!Vue.prototype.hasOwnProperty('$i18n')) {
+    // $FlowFixMe
+    Object.defineProperty(Vue.prototype, '$i18n', {
+      get () { return this._i18n }
+    })
+  }
+
+  Vue.prototype.$t = function (key: Path, ...values: any): TranslateResult {
+    const i18n = this.$i18n
+    return i18n._t(key, i18n.locale, i18n._getMessages(), this, ...values)
+  }
+
+  Vue.prototype.$tc = function (key: Path, choice?: number, ...values: any): TranslateResult {
+    const i18n = this.$i18n
+    return i18n._tc(key, i18n.locale, i18n._getMessages(), this, choice, ...values)
+  }
+
+  Vue.prototype.$te = function (key: Path, locale?: Locale): boolean {
+    const i18n = this.$i18n
+    return i18n._te(key, i18n.locale, i18n._getMessages(), locale)
+  }
+
+  Vue.prototype.$d = function (value: number | Date, ...args: any): DateTimeFormatResult {
+    return this.$i18n.d(value, ...args)
+  }
+
+  Vue.prototype.$n = function (value: number, ...args: any): NumberFormatResult {
+    return this.$i18n.n(value, ...args)
+  }
+}

+ 114 - 0
plugin/vue-i18n/src/format.js

@@ -0,0 +1,114 @@
+/* @flow */
+
+import { warn, isObject } from './util'
+
+export default class BaseFormatter {
+  _caches: { [key: string]: Array<Token> }
+
+  constructor () {
+    this._caches = Object.create(null)
+  }
+
+  interpolate (message: string, values: any): Array<any> {
+    if (!values) {
+      return [message]
+    }
+    let tokens: Array<Token> = this._caches[message]
+    if (!tokens) {
+      tokens = parse(message)
+      this._caches[message] = tokens
+    }
+    return compile(tokens, values)
+  }
+}
+
+type Token = {
+  type: 'text' | 'named' | 'list' | 'unknown',
+  value: string
+}
+
+const RE_TOKEN_LIST_VALUE: RegExp = /^(?:\d)+/
+const RE_TOKEN_NAMED_VALUE: RegExp = /^(?:\w)+/
+
+export function parse (format: string): Array<Token> {
+  const tokens: Array<Token> = []
+  let position: number = 0
+
+  let text: string = ''
+  while (position < format.length) {
+    let char: string = format[position++]
+    if (char === '{') {
+      if (text) {
+        tokens.push({ type: 'text', value: text })
+      }
+
+      text = ''
+      let sub: string = ''
+      char = format[position++]
+      while (char !== undefined && char !== '}') {
+        sub += char
+        char = format[position++]
+      }
+      const isClosed = char === '}'
+
+      const type = RE_TOKEN_LIST_VALUE.test(sub)
+        ? 'list'
+        : isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
+          ? 'named'
+          : 'unknown'
+      tokens.push({ value: sub, type })
+    } else if (char === '%') {
+      // when found rails i18n syntax, skip text capture
+      if (format[(position)] !== '{') {
+        text += char
+      }
+    } else {
+      text += char
+    }
+  }
+
+  text && tokens.push({ type: 'text', value: text })
+
+  return tokens
+}
+
+export function compile (tokens: Array<Token>, values: Object | Array<any>): Array<any> {
+  const compiled: Array<any> = []
+  let index: number = 0
+
+  const mode: string = Array.isArray(values)
+    ? 'list'
+    : isObject(values)
+      ? 'named'
+      : 'unknown'
+  if (mode === 'unknown') { return compiled }
+
+  while (index < tokens.length) {
+    const token: Token = tokens[index]
+    switch (token.type) {
+      case 'text':
+        compiled.push(token.value)
+        break
+      case 'list':
+        compiled.push(values[parseInt(token.value, 10)])
+        break
+      case 'named':
+        if (mode === 'named') {
+          compiled.push((values: any)[token.value])
+        } else {
+          if (process.env.NODE_ENV !== 'production') {
+            warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`)
+          }
+        }
+        break
+      case 'unknown':
+        if (process.env.NODE_ENV !== 'production') {
+          warn(`Detect 'unknown' type of token!`)
+        }
+        break
+    }
+    index++
+  }
+
+  return compiled
+}

+ 1065 - 0
plugin/vue-i18n/src/index.js

@@ -0,0 +1,1065 @@
+/* @flow */
+
+import { install, Vue } from './install'
+import {
+  warn,
+  error,
+  isNull,
+  parseArgs,
+  isPlainObject,
+  isObject,
+  isArray,
+  isBoolean,
+  isString,
+  isFunction,
+  looseClone,
+  remove,
+  includes,
+  merge,
+  numberFormatKeys
+} from './util'
+import BaseFormatter from './format'
+import I18nPath from './path'
+
+import type { PathValue } from './path'
+
+const htmlTagMatcher = /<\/?[\w\s="/.':;#-\/]+>/
+const linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g
+const linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/
+const bracketsMatcher = /[()]/g
+const defaultModifiers = {
+  'upper': str => str.toLocaleUpperCase(),
+  'lower': str => str.toLocaleLowerCase(),
+  'capitalize': str => `${str.charAt(0).toLocaleUpperCase()}${str.substr(1)}`
+}
+
+const defaultFormatter = new BaseFormatter()
+
+export default class VueI18n {
+  static install: () => void
+  static version: string
+  static availabilities: IntlAvailability
+
+  _vm: any
+  _formatter: Formatter
+  _modifiers: Modifiers
+  _root: any
+  _sync: boolean
+  _fallbackRoot: boolean
+  _localeChainCache: { [key: string]: Array<Locale>; }
+  _missing: ?MissingHandler
+  _exist: Function
+  _silentTranslationWarn: boolean | RegExp
+  _silentFallbackWarn: boolean | RegExp
+  _formatFallbackMessages: boolean
+  _dateTimeFormatters: Object
+  _numberFormatters: Object
+  _path: I18nPath
+  _dataListeners: Array<any>
+  _componentInstanceCreatedListener: ?ComponentInstanceCreatedListener
+  _preserveDirectiveContent: boolean
+  _warnHtmlInMessage: WarnHtmlInMessageLevel
+  _postTranslation: ?PostTranslationHandler
+  pluralizationRules: {
+    [lang: string]: (choice: number, choicesLength: number) => number
+  }
+  getChoiceIndex: GetChoiceIndex
+
+  constructor (options: I18nOptions = {}) {
+    // Auto install if it is not done yet and `window` has `Vue`.
+    // To allow users to avoid auto-installation in some cases,
+    // this code should be placed here. See #290
+    /* istanbul ignore if */
+    if (!Vue && typeof window !== 'undefined' && window.Vue) {
+      install(window.Vue)
+    }
+
+    const locale: Locale = options.locale || 'en-US'
+    const fallbackLocale: FallbackLocale = options.fallbackLocale === false
+      ? false
+      : options.fallbackLocale || 'en-US'
+    const messages: LocaleMessages = options.messages || {}
+    const dateTimeFormats = options.dateTimeFormats || {}
+    const numberFormats = options.numberFormats || {}
+
+    this._vm = null
+    this._formatter = options.formatter || defaultFormatter
+    this._modifiers = options.modifiers || {}
+    this._missing = options.missing || null
+    this._root = options.root || null
+    this._sync = options.sync === undefined ? true : !!options.sync
+    this._fallbackRoot = options.fallbackRoot === undefined
+      ? true
+      : !!options.fallbackRoot
+    this._formatFallbackMessages = options.formatFallbackMessages === undefined
+      ? false
+      : !!options.formatFallbackMessages
+    this._silentTranslationWarn = options.silentTranslationWarn === undefined
+      ? false
+      : options.silentTranslationWarn
+    this._silentFallbackWarn = options.silentFallbackWarn === undefined
+      ? false
+      : !!options.silentFallbackWarn
+    this._dateTimeFormatters = {}
+    this._numberFormatters = {}
+    this._path = new I18nPath()
+    this._dataListeners = []
+    this._componentInstanceCreatedListener = options.componentInstanceCreatedListener || null
+    this._preserveDirectiveContent = options.preserveDirectiveContent === undefined
+      ? false
+      : !!options.preserveDirectiveContent
+    this.pluralizationRules = options.pluralizationRules || {}
+    this._warnHtmlInMessage = options.warnHtmlInMessage || 'off'
+    this._postTranslation = options.postTranslation || null
+
+    /**
+     * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
+     * @param choicesLength {number} an overall amount of available choices
+     * @returns a final choice index
+    */
+    this.getChoiceIndex = (choice: number, choicesLength: number): number => {
+      const thisPrototype = Object.getPrototypeOf(this)
+      if (thisPrototype && thisPrototype.getChoiceIndex) {
+        const prototypeGetChoiceIndex = (thisPrototype.getChoiceIndex: any)
+        return (prototypeGetChoiceIndex: GetChoiceIndex).call(this, choice, choicesLength)
+      }
+
+      // Default (old) getChoiceIndex implementation - english-compatible
+      const defaultImpl = (_choice: number, _choicesLength: number) => {
+        _choice = Math.abs(_choice)
+
+        if (_choicesLength === 2) {
+          return _choice
+            ? _choice > 1
+              ? 1
+              : 0
+            : 1
+        }
+
+        return _choice ? Math.min(_choice, 2) : 0
+      }
+
+      if (this.locale in this.pluralizationRules) {
+        return this.pluralizationRules[this.locale].apply(this, [choice, choicesLength])
+      } else {
+        return defaultImpl(choice, choicesLength)
+      }
+    }
+
+
+    this._exist = (message: Object, key: Path): boolean => {
+      if (!message || !key) { return false }
+      if (!isNull(this._path.getPathValue(message, key))) { return true }
+      // fallback for flat key
+      if (message[key]) { return true }
+      return false
+    }
+
+    if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+      Object.keys(messages).forEach(locale => {
+        this._checkLocaleMessage(locale, this._warnHtmlInMessage, messages[locale])
+      })
+    }
+
+    this._initVM({
+      locale,
+      fallbackLocale,
+      messages,
+      dateTimeFormats,
+      numberFormats
+    })
+  }
+
+  _checkLocaleMessage (locale: Locale, level: WarnHtmlInMessageLevel, message: LocaleMessageObject): void {
+    const paths: Array<string> = []
+
+    const fn = (level: WarnHtmlInMessageLevel, locale: Locale, message: any, paths: Array<string>) => {
+      if (isPlainObject(message)) {
+        Object.keys(message).forEach(key => {
+          const val = message[key]
+          if (isPlainObject(val)) {
+            paths.push(key)
+            paths.push('.')
+            fn(level, locale, val, paths)
+            paths.pop()
+            paths.pop()
+          } else {
+            paths.push(key)
+            fn(level, locale, val, paths)
+            paths.pop()
+          }
+        })
+      } else if (isArray(message)) {
+        message.forEach((item, index) => {
+          if (isPlainObject(item)) {
+            paths.push(`[${index}]`)
+            paths.push('.')
+            fn(level, locale, item, paths)
+            paths.pop()
+            paths.pop()
+          } else {
+            paths.push(`[${index}]`)
+            fn(level, locale, item, paths)
+            paths.pop()
+          }
+        })
+      } else if (isString(message)) {
+        const ret = htmlTagMatcher.test(message)
+        if (ret) {
+          const msg = `Detected HTML in message '${message}' of keypath '${paths.join('')}' at '${locale}'. Consider component interpolation with '<i18n>' to avoid XSS. See https://bit.ly/2ZqJzkp`
+          if (level === 'warn') {
+            warn(msg)
+          } else if (level === 'error') {
+            error(msg)
+          }
+        }
+      }
+    }
+
+    fn(level, locale, message, paths)
+  }
+
+  _initVM (data: {
+    locale: Locale,
+    fallbackLocale: FallbackLocale,
+    messages: LocaleMessages,
+    dateTimeFormats: DateTimeFormats,
+    numberFormats: NumberFormats
+  }): void {
+    const silent = Vue.config.silent
+    Vue.config.silent = true
+    this._vm = new Vue({ data })
+    Vue.config.silent = silent
+  }
+
+  destroyVM (): void {
+    this._vm.$destroy()
+  }
+
+  subscribeDataChanging (vm: any): void {
+    this._dataListeners.push(vm)
+  }
+
+  unsubscribeDataChanging (vm: any): void {
+    remove(this._dataListeners, vm)
+  }
+
+  watchI18nData (): Function {
+    const self = this
+    return this._vm.$watch('$data', () => {
+      let i = self._dataListeners.length
+      while (i--) {
+        Vue.nextTick(() => {
+          self._dataListeners[i] && self._dataListeners[i].$forceUpdate()
+        })
+      }
+    }, { deep: true })
+  }
+
+  watchLocale (): ?Function {
+    /* istanbul ignore if */
+    if (!this._sync || !this._root) { return null }
+    const target: any = this._vm
+    return this._root.$i18n.vm.$watch('locale', (val) => {
+      target.$set(target, 'locale', val)
+      target.$forceUpdate()
+    }, { immediate: true })
+  }
+
+  onComponentInstanceCreated (newI18n: I18n) {
+    if (this._componentInstanceCreatedListener) {
+      this._componentInstanceCreatedListener(newI18n, this)
+    }
+  }
+
+  get vm (): any { return this._vm }
+
+  get messages (): LocaleMessages { return looseClone(this._getMessages()) }
+  get dateTimeFormats (): DateTimeFormats { return looseClone(this._getDateTimeFormats()) }
+  get numberFormats (): NumberFormats { return looseClone(this._getNumberFormats()) }
+  get availableLocales (): Locale[] { return Object.keys(this.messages).sort() }
+
+  get locale (): Locale { return this._vm.locale }
+  set locale (locale: Locale): void {
+    this._vm.$set(this._vm, 'locale', locale)
+  }
+
+  get fallbackLocale (): FallbackLocale { return this._vm.fallbackLocale }
+  set fallbackLocale (locale: FallbackLocale): void {
+    this._localeChainCache = {}
+    this._vm.$set(this._vm, 'fallbackLocale', locale)
+  }
+
+  get formatFallbackMessages (): boolean { return this._formatFallbackMessages }
+  set formatFallbackMessages (fallback: boolean): void { this._formatFallbackMessages = fallback }
+
+  get missing (): ?MissingHandler { return this._missing }
+  set missing (handler: MissingHandler): void { this._missing = handler }
+
+  get formatter (): Formatter { return this._formatter }
+  set formatter (formatter: Formatter): void { this._formatter = formatter }
+
+  get silentTranslationWarn (): boolean | RegExp { return this._silentTranslationWarn }
+  set silentTranslationWarn (silent: boolean | RegExp): void { this._silentTranslationWarn = silent }
+
+  get silentFallbackWarn (): boolean | RegExp { return this._silentFallbackWarn }
+  set silentFallbackWarn (silent: boolean | RegExp): void { this._silentFallbackWarn = silent }
+
+  get preserveDirectiveContent (): boolean { return this._preserveDirectiveContent }
+  set preserveDirectiveContent (preserve: boolean): void { this._preserveDirectiveContent = preserve }
+
+  get warnHtmlInMessage (): WarnHtmlInMessageLevel { return this._warnHtmlInMessage }
+  set warnHtmlInMessage (level: WarnHtmlInMessageLevel): void {
+    const orgLevel = this._warnHtmlInMessage
+    this._warnHtmlInMessage = level
+    if (orgLevel !== level && (level === 'warn' || level === 'error')) {
+      const messages = this._getMessages()
+      Object.keys(messages).forEach(locale => {
+        this._checkLocaleMessage(locale, this._warnHtmlInMessage, messages[locale])
+      })
+    }
+  }
+
+  get postTranslation (): ?PostTranslationHandler { return this._postTranslation }
+  set postTranslation (handler: PostTranslationHandler): void { this._postTranslation = handler }
+
+  _getMessages (): LocaleMessages { return this._vm.messages }
+  _getDateTimeFormats (): DateTimeFormats { return this._vm.dateTimeFormats }
+  _getNumberFormats (): NumberFormats { return this._vm.numberFormats }
+
+  _warnDefault (locale: Locale, key: Path, result: ?any, vm: ?any, values: any, interpolateMode: string): ?string {
+    if (!isNull(result)) { return result }
+    if (this._missing) {
+      const missingRet = this._missing.apply(null, [locale, key, vm, values])
+      if (isString(missingRet)) {
+        return missingRet
+      }
+    } else {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key)) {
+        warn(
+          `Cannot translate the value of keypath '${key}'. ` +
+          'Use the value of keypath as default.'
+        )
+      }
+    }
+
+    if (this._formatFallbackMessages) {
+      const parsedArgs = parseArgs(...values)
+      return this._render(key, interpolateMode, parsedArgs.params, key)
+    } else {
+      return key
+    }
+  }
+
+  _isFallbackRoot (val: any): boolean {
+    return !val && !isNull(this._root) && this._fallbackRoot
+  }
+
+  _isSilentFallbackWarn (key: Path): boolean {
+    return this._silentFallbackWarn instanceof RegExp
+      ? this._silentFallbackWarn.test(key)
+      : this._silentFallbackWarn
+  }
+
+  _isSilentFallback (locale: Locale, key: Path): boolean {
+    return this._isSilentFallbackWarn(key) && (this._isFallbackRoot() || locale !== this.fallbackLocale)
+  }
+
+  _isSilentTranslationWarn (key: Path): boolean {
+    return this._silentTranslationWarn instanceof RegExp
+      ? this._silentTranslationWarn.test(key)
+      : this._silentTranslationWarn
+  }
+
+  _interpolate (
+    locale: Locale,
+    message: LocaleMessageObject,
+    key: Path,
+    host: any,
+    interpolateMode: string,
+    values: any,
+    visitedLinkStack: Array<string>
+  ): any {
+    if (!message) { return null }
+
+    const pathRet: PathValue = this._path.getPathValue(message, key)
+    if (isArray(pathRet) || isPlainObject(pathRet)) { return pathRet }
+
+    let ret: mixed
+    if (isNull(pathRet)) {
+      /* istanbul ignore else */
+      if (isPlainObject(message)) {
+        ret = message[key]
+        if (!(isString(ret) || isFunction(ret))) {
+          if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+            warn(`Value of key '${key}' is not a string or function !`)
+          }
+          return null
+        }
+      } else {
+        return null
+      }
+    } else {
+      /* istanbul ignore else */
+      if (isString(pathRet) || isFunction(pathRet)) {
+        ret = pathRet
+      } else {
+        if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallback(locale, key)) {
+          warn(`Value of key '${key}' is not a string or function!`)
+        }
+        return null
+      }
+    }
+
+    // Check for the existence of links within the translated string
+    if (isString(ret) && (ret.indexOf('@:') >= 0 || ret.indexOf('@.') >= 0)) {
+      ret = this._link(locale, message, ret, host, 'raw', values, visitedLinkStack)
+    }
+
+    return this._render(ret, interpolateMode, values, key)
+  }
+
+  _link (
+    locale: Locale,
+    message: LocaleMessageObject,
+    str: string,
+    host: any,
+    interpolateMode: string,
+    values: any,
+    visitedLinkStack: Array<string>
+  ): any {
+    let ret: string = str
+
+    // Match all the links within the local
+    // We are going to replace each of
+    // them with its translation
+    const matches: any = ret.match(linkKeyMatcher)
+    for (let idx in matches) {
+      // ie compatible: filter custom array
+      // prototype method
+      if (!matches.hasOwnProperty(idx)) {
+        continue
+      }
+      const link: string = matches[idx]
+      const linkKeyPrefixMatches: any = link.match(linkKeyPrefixMatcher)
+      const [linkPrefix, formatterName] = linkKeyPrefixMatches
+
+      // Remove the leading @:, @.case: and the brackets
+      const linkPlaceholder: string = link.replace(linkPrefix, '').replace(bracketsMatcher, '')
+
+      if (includes(visitedLinkStack, linkPlaceholder)) {
+        if (process.env.NODE_ENV !== 'production') {
+          warn(`Circular reference found. "${link}" is already visited in the chain of ${visitedLinkStack.reverse().join(' <- ')}`)
+        }
+        return ret
+      }
+      visitedLinkStack.push(linkPlaceholder)
+
+      // Translate the link
+      let translated: any = this._interpolate(
+        locale, message, linkPlaceholder, host,
+        interpolateMode === 'raw' ? 'string' : interpolateMode,
+        interpolateMode === 'raw' ? undefined : values,
+        visitedLinkStack
+      )
+
+      if (this._isFallbackRoot(translated)) {
+        if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(linkPlaceholder)) {
+          warn(`Fall back to translate the link placeholder '${linkPlaceholder}' with root locale.`)
+        }
+        /* istanbul ignore if */
+        if (!this._root) { throw Error('unexpected error') }
+        const root: any = this._root.$i18n
+        translated = root._translate(
+          root._getMessages(), root.locale, root.fallbackLocale,
+          linkPlaceholder, host, interpolateMode, values
+        )
+      }
+      translated = this._warnDefault(
+        locale, linkPlaceholder, translated, host,
+        isArray(values) ? values : [values],
+        interpolateMode
+      )
+
+      if (this._modifiers.hasOwnProperty(formatterName)) {
+        translated = this._modifiers[formatterName](translated)
+      } else if (defaultModifiers.hasOwnProperty(formatterName)) {
+        translated = defaultModifiers[formatterName](translated)
+      }
+
+      visitedLinkStack.pop()
+
+      // Replace the link with the translated
+      ret = !translated ? ret : ret.replace(link, translated)
+    }
+
+    return ret
+  }
+
+  _createMessageContext (values: any): MessageContext {
+    const _list = isArray(values) ? values : []
+    const _named = isObject(values) ? values : {}
+    const list = (index: number): mixed => _list[index]
+    const named = (key: string): mixed => _named[key]
+    return {
+      list,
+      named
+    }
+  }
+
+  _render (message: string | MessageFunction, interpolateMode: string, values: any, path: string): any {
+    if (isFunction(message)) {
+      return message(this._createMessageContext(values))
+    }
+
+    let ret = this._formatter.interpolate(message, values, path)
+
+    // If the custom formatter refuses to work - apply the default one
+    if (!ret) {
+      ret = defaultFormatter.interpolate(message, values, path)
+    }
+
+    // if interpolateMode is **not** 'string' ('row'),
+    // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
+    return interpolateMode === 'string' && !isString(ret) ? ret.join('') : ret
+  }
+
+  _appendItemToChain (chain: Array<Locale>, item: Locale, blocks: any): any {
+    let follow = false
+    if (!includes(chain, item)) {
+      follow = true
+      if (item) {
+        follow = item[item.length - 1] !== '!'
+        item = item.replace(/!/g, '')
+        chain.push(item)
+        if (blocks && blocks[item]) {
+          follow = blocks[item]
+        }
+      }
+    }
+    return follow
+  }
+
+  _appendLocaleToChain (chain: Array<Locale>, locale: Locale, blocks: any): any {
+    let follow
+    const tokens = locale.split('-')
+    do {
+      const item = tokens.join('-')
+      follow = this._appendItemToChain(chain, item, blocks)
+      tokens.splice(-1, 1)
+    } while (tokens.length && (follow === true))
+    return follow
+  }
+
+  _appendBlockToChain (chain: Array<Locale>, block: Array<Locale> | Object, blocks: any): any {
+    let follow = true
+    for (let i = 0; (i < block.length) && (isBoolean(follow)); i++) {
+      const locale = block[i]
+      if (isString(locale)) {
+        follow = this._appendLocaleToChain(chain, locale, blocks)
+      }
+    }
+    return follow
+  }
+
+  _getLocaleChain (start: Locale, fallbackLocale: FallbackLocale): Array<Locale> {
+    if (start === '') { return [] }
+
+    if (!this._localeChainCache) {
+      this._localeChainCache = {}
+    }
+
+    let chain = this._localeChainCache[start]
+    if (!chain) {
+      if (!fallbackLocale) {
+        fallbackLocale = this.fallbackLocale
+      }
+      chain = []
+
+      // first block defined by start
+      let block = [start]
+
+      // while any intervening block found
+      while (isArray(block)) {
+        block = this._appendBlockToChain(
+          chain,
+          block,
+          fallbackLocale
+        )
+      }
+
+      // last block defined by default
+      let defaults
+      if (isArray(fallbackLocale)) {
+        defaults = fallbackLocale
+      } else if (isObject(fallbackLocale)) {
+        /* $FlowFixMe */
+        if (fallbackLocale['default']) {
+          defaults = fallbackLocale['default']
+        } else {
+          defaults = null
+        }
+      } else {
+        defaults = fallbackLocale
+      }
+
+      // convert defaults to array
+      if (isString(defaults)) {
+        block = [defaults]
+      } else {
+        block = defaults
+      }
+      if (block) {
+        this._appendBlockToChain(
+          chain,
+          block,
+          null
+        )
+      }
+      this._localeChainCache[start] = chain
+    }
+    return chain
+  }
+
+  _translate (
+    messages: LocaleMessages,
+    locale: Locale,
+    fallback: FallbackLocale,
+    key: Path,
+    host: any,
+    interpolateMode: string,
+    args: any
+  ): any {
+    const chain = this._getLocaleChain(locale, fallback)
+    let res
+    for (let i = 0; i < chain.length; i++) {
+      const step = chain[i]
+      res =
+        this._interpolate(step, messages[step], key, host, interpolateMode, args, [key])
+      if (!isNull(res)) {
+        if (step !== locale && process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+          warn(("Fall back to translate the keypath '" + key + "' with '" + step + "' locale."))
+        }
+        return res
+      }
+    }
+    return null
+  }
+
+  _t (key: Path, _locale: Locale, messages: LocaleMessages, host: any, ...values: any): any {
+    if (!key) { return '' }
+
+    const parsedArgs = parseArgs(...values)
+    const locale: Locale = parsedArgs.locale || _locale
+
+    let ret: any = this._translate(
+      messages, locale, this.fallbackLocale, key,
+      host, 'string', parsedArgs.params
+    )
+    if (this._isFallbackRoot(ret)) {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(`Fall back to translate the keypath '${key}' with root locale.`)
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$t(key, ...values)
+    } else {
+      ret = this._warnDefault(locale, key, ret, host, values, 'string')
+      if (this._postTranslation && ret !== null && ret !== undefined) {
+        ret = this._postTranslation(ret, key)
+      }
+      return ret
+    }
+  }
+
+  t (key: Path, ...values: any): TranslateResult {
+    return this._t(key, this.locale, this._getMessages(), null, ...values)
+  }
+
+  _i (key: Path, locale: Locale, messages: LocaleMessages, host: any, values: Object): any {
+    const ret: any =
+      this._translate(messages, locale, this.fallbackLocale, key, host, 'raw', values)
+    if (this._isFallbackRoot(ret)) {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key)) {
+        warn(`Fall back to interpolate the keypath '${key}' with root locale.`)
+      }
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n.i(key, locale, values)
+    } else {
+      return this._warnDefault(locale, key, ret, host, [values], 'raw')
+    }
+  }
+
+  i (key: Path, locale: Locale, values: Object): TranslateResult {
+    /* istanbul ignore if */
+    if (!key) { return '' }
+
+    if (!isString(locale)) {
+      locale = this.locale
+    }
+
+    return this._i(key, locale, this._getMessages(), null, values)
+  }
+
+  _tc (
+    key: Path,
+    _locale: Locale,
+    messages: LocaleMessages,
+    host: any,
+    choice?: number,
+    ...values: any
+  ): any {
+    if (!key) { return '' }
+    if (choice === undefined) {
+      choice = 1
+    }
+
+    const predefined = { 'count': choice, 'n': choice }
+    const parsedArgs = parseArgs(...values)
+    parsedArgs.params = Object.assign(predefined, parsedArgs.params)
+    values = parsedArgs.locale === null ? [parsedArgs.params] : [parsedArgs.locale, parsedArgs.params]
+    return this.fetchChoice(this._t(key, _locale, messages, host, ...values), choice)
+  }
+
+  fetchChoice (message: string, choice: number): ?string {
+    /* istanbul ignore if */
+    if (!message && !isString(message)) { return null }
+    const choices: Array<string> = message.split('|')
+
+    choice = this.getChoiceIndex(choice, choices.length)
+    if (!choices[choice]) { return message }
+    return choices[choice].trim()
+  }
+
+  tc (key: Path, choice?: number, ...values: any): TranslateResult {
+    return this._tc(key, this.locale, this._getMessages(), null, choice, ...values)
+  }
+
+  _te (key: Path, locale: Locale, messages: LocaleMessages, ...args: any): boolean {
+    const _locale: Locale = parseArgs(...args).locale || locale
+    return this._exist(messages[_locale], key)
+  }
+
+  te (key: Path, locale?: Locale): boolean {
+    return this._te(key, this.locale, this._getMessages(), locale)
+  }
+
+  getLocaleMessage (locale: Locale): LocaleMessageObject {
+    return looseClone(this._vm.messages[locale] || {})
+  }
+
+  setLocaleMessage (locale: Locale, message: LocaleMessageObject): void {
+    if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+      this._checkLocaleMessage(locale, this._warnHtmlInMessage, message)
+    }
+    this._vm.$set(this._vm.messages, locale, message)
+  }
+
+  mergeLocaleMessage (locale: Locale, message: LocaleMessageObject): void {
+    if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
+      this._checkLocaleMessage(locale, this._warnHtmlInMessage, message)
+    }
+    this._vm.$set(this._vm.messages, locale, merge({}, this._vm.messages[locale] || {}, message))
+  }
+
+  getDateTimeFormat (locale: Locale): DateTimeFormat {
+    return looseClone(this._vm.dateTimeFormats[locale] || {})
+  }
+
+  setDateTimeFormat (locale: Locale, format: DateTimeFormat): void {
+    this._vm.$set(this._vm.dateTimeFormats, locale, format)
+    this._clearDateTimeFormat(locale, format)
+  }
+
+  mergeDateTimeFormat (locale: Locale, format: DateTimeFormat): void {
+    this._vm.$set(this._vm.dateTimeFormats, locale, merge(this._vm.dateTimeFormats[locale] || {}, format))
+    this._clearDateTimeFormat(locale, format)
+  }
+
+  _clearDateTimeFormat (locale: Locale, format: DateTimeFormat): void {
+    for (let key in format) {
+      const id = `${locale}__${key}`
+
+      if (!this._dateTimeFormatters.hasOwnProperty(id)) {
+        continue
+      }
+
+      delete this._dateTimeFormatters[id]
+    }
+  }
+
+  _localizeDateTime (
+    value: number | Date,
+    locale: Locale,
+    fallback: FallbackLocale,
+    dateTimeFormats: DateTimeFormats,
+    key: string
+  ): ?DateTimeFormatResult {
+    let _locale: Locale = locale
+    let formats: DateTimeFormat = dateTimeFormats[_locale]
+
+    const chain = this._getLocaleChain(locale, fallback)
+    for (let i = 0; i < chain.length; i++) {
+      const current = _locale
+      const step = chain[i]
+      formats = dateTimeFormats[step]
+      _locale = step
+      // fallback locale
+      if (isNull(formats) || isNull(formats[key])) {
+        if (step !== locale && process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+          warn(`Fall back to '${step}' datetime formats from '${current}' datetime formats.`)
+        }
+      } else {
+        break
+      }
+    }
+
+    if (isNull(formats) || isNull(formats[key])) {
+      return null
+    } else {
+      const format: ?DateTimeFormatOptions = formats[key]
+      const id = `${_locale}__${key}`
+      let formatter = this._dateTimeFormatters[id]
+      if (!formatter) {
+        formatter = this._dateTimeFormatters[id] = new Intl.DateTimeFormat(_locale, format)
+      }
+      return formatter.format(value)
+    }
+  }
+
+  _d (value: number | Date, locale: Locale, key: ?string): DateTimeFormatResult {
+    /* istanbul ignore if */
+    if (process.env.NODE_ENV !== 'production' && !VueI18n.availabilities.dateTimeFormat) {
+      warn('Cannot format a Date value due to not supported Intl.DateTimeFormat.')
+      return ''
+    }
+
+    if (!key) {
+      return new Intl.DateTimeFormat(locale).format(value)
+    }
+
+    const ret: ?DateTimeFormatResult =
+      this._localizeDateTime(value, locale, this.fallbackLocale, this._getDateTimeFormats(), key)
+    if (this._isFallbackRoot(ret)) {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(`Fall back to datetime localization of root: key '${key}'.`)
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n.d(value, key, locale)
+    } else {
+      return ret || ''
+    }
+  }
+
+  d (value: number | Date, ...args: any): DateTimeFormatResult {
+    let locale: Locale = this.locale
+    let key: ?string = null
+
+    if (args.length === 1) {
+      if (isString(args[0])) {
+        key = args[0]
+      } else if (isObject(args[0])) {
+        if (args[0].locale) {
+          locale = args[0].locale
+        }
+        if (args[0].key) {
+          key = args[0].key
+        }
+      }
+    } else if (args.length === 2) {
+      if (isString(args[0])) {
+        key = args[0]
+      }
+      if (isString(args[1])) {
+        locale = args[1]
+      }
+    }
+
+    return this._d(value, locale, key)
+  }
+
+  getNumberFormat (locale: Locale): NumberFormat {
+    return looseClone(this._vm.numberFormats[locale] || {})
+  }
+
+  setNumberFormat (locale: Locale, format: NumberFormat): void {
+    this._vm.$set(this._vm.numberFormats, locale, format)
+    this._clearNumberFormat(locale, format)
+  }
+
+  mergeNumberFormat (locale: Locale, format: NumberFormat): void {
+    this._vm.$set(this._vm.numberFormats, locale, merge(this._vm.numberFormats[locale] || {}, format))
+    this._clearNumberFormat(locale, format)
+  }
+
+  _clearNumberFormat (locale: Locale, format: NumberFormat): void {
+    for (let key in format) {
+      const id = `${locale}__${key}`
+
+      if (!this._numberFormatters.hasOwnProperty(id)) {
+        continue
+      }
+
+      delete this._numberFormatters[id]
+    }
+  }
+
+  _getNumberFormatter (
+    value: number,
+    locale: Locale,
+    fallback: FallbackLocale,
+    numberFormats: NumberFormats,
+    key: string,
+    options: ?NumberFormatOptions
+  ): ?Object {
+    let _locale: Locale = locale
+    let formats: NumberFormat = numberFormats[_locale]
+
+    const chain = this._getLocaleChain(locale, fallback)
+    for (let i = 0; i < chain.length; i++) {
+      const current = _locale
+      const step = chain[i]
+      formats = numberFormats[step]
+      _locale = step
+      // fallback locale
+      if (isNull(formats) || isNull(formats[key])) {
+        if (step !== locale && process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+          warn(`Fall back to '${step}' number formats from '${current}' number formats.`)
+        }
+      } else {
+        break
+      }
+    }
+
+    if (isNull(formats) || isNull(formats[key])) {
+      return null
+    } else {
+      const format: ?NumberFormatOptions = formats[key]
+
+      let formatter
+      if (options) {
+        // If options specified - create one time number formatter
+        formatter = new Intl.NumberFormat(_locale, Object.assign({}, format, options))
+      } else {
+        const id = `${_locale}__${key}`
+        formatter = this._numberFormatters[id]
+        if (!formatter) {
+          formatter = this._numberFormatters[id] = new Intl.NumberFormat(_locale, format)
+        }
+      }
+      return formatter
+    }
+  }
+
+  _n (value: number, locale: Locale, key: ?string, options: ?NumberFormatOptions): NumberFormatResult {
+    /* istanbul ignore if */
+    if (!VueI18n.availabilities.numberFormat) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot format a Number value due to not supported Intl.NumberFormat.')
+      }
+      return ''
+    }
+
+    if (!key) {
+      const nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options)
+      return nf.format(value)
+    }
+
+    const formatter: ?Object = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options)
+    const ret: ?NumberFormatResult = formatter && formatter.format(value)
+    if (this._isFallbackRoot(ret)) {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key) && !this._isSilentFallbackWarn(key)) {
+        warn(`Fall back to number localization of root: key '${key}'.`)
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n.n(value, Object.assign({}, { key, locale }, options))
+    } else {
+      return ret || ''
+    }
+  }
+
+  n (value: number, ...args: any): NumberFormatResult {
+    let locale: Locale = this.locale
+    let key: ?string = null
+    let options: ?NumberFormatOptions = null
+
+    if (args.length === 1) {
+      if (isString(args[0])) {
+        key = args[0]
+      } else if (isObject(args[0])) {
+        if (args[0].locale) {
+          locale = args[0].locale
+        }
+        if (args[0].key) {
+          key = args[0].key
+        }
+
+        // Filter out number format options only
+        options = Object.keys(args[0]).reduce((acc, key) => {
+          if (includes(numberFormatKeys, key)) {
+            return Object.assign({}, acc, { [key]: args[0][key] })
+          }
+          return acc
+        }, null)
+      }
+    } else if (args.length === 2) {
+      if (isString(args[0])) {
+        key = args[0]
+      }
+      if (isString(args[1])) {
+        locale = args[1]
+      }
+    }
+
+    return this._n(value, locale, key, options)
+  }
+
+  _ntp (value: number, locale: Locale, key: ?string, options: ?NumberFormatOptions): NumberFormatToPartsResult {
+    /* istanbul ignore if */
+    if (!VueI18n.availabilities.numberFormat) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot format to parts a Number value due to not supported Intl.NumberFormat.')
+      }
+      return []
+    }
+
+    if (!key) {
+      const nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options)
+      return nf.formatToParts(value)
+    }
+
+    const formatter: ?Object = this._getNumberFormatter(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options)
+    const ret: ?NumberFormatToPartsResult = formatter && formatter.formatToParts(value)
+    if (this._isFallbackRoot(ret)) {
+      if (process.env.NODE_ENV !== 'production' && !this._isSilentTranslationWarn(key)) {
+        warn(`Fall back to format number to parts of root: key '${key}' .`)
+      }
+      /* istanbul ignore if */
+      if (!this._root) { throw Error('unexpected error') }
+      return this._root.$i18n._ntp(value, locale, key, options)
+    } else {
+      return ret || []
+    }
+  }
+}
+
+let availabilities: IntlAvailability
+// $FlowFixMe
+Object.defineProperty(VueI18n, 'availabilities', {
+  get () {
+    if (!availabilities) {
+      const intlDefined = typeof Intl !== 'undefined'
+      availabilities = {
+        dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
+        numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
+      }
+    }
+
+    return availabilities
+  }
+})
+
+VueI18n.install = install
+VueI18n.version = '__VERSION__'

+ 40 - 0
plugin/vue-i18n/src/install.js

@@ -0,0 +1,40 @@
+import { warn } from './util'
+import extend from './extend'
+import mixin from './mixin'
+import interpolationComponent from './components/interpolation'
+import numberComponent from './components/number'
+import { bind, update, unbind } from './directive'
+
+export let Vue
+
+export function install (_Vue) {
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && install.installed && _Vue === Vue) {
+    warn('already installed.')
+    return
+  }
+  install.installed = true
+
+  Vue = _Vue
+
+  const version = (Vue.version && Number(Vue.version.split('.')[0])) || -1
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && version < 2) {
+    warn(`vue-i18n (${install.version}) need to use Vue 2.0 or later (Vue: ${Vue.version}).`)
+    return
+  }
+
+  extend(Vue)
+  Vue.mixin(mixin)
+  Vue.directive('t', { bind, update, unbind })
+  Vue.component(interpolationComponent.name, interpolationComponent)
+  Vue.component(numberComponent.name, numberComponent)
+
+  // use simple mergeStrategies to prevent i18n instance lose '__proto__'
+  const strats = Vue.config.optionMergeStrategies
+  strats.i18n = function (parentVal, childVal) {
+    return childVal === undefined
+      ? parentVal
+      : childVal
+  }
+}

+ 139 - 0
plugin/vue-i18n/src/mixin.js

@@ -0,0 +1,139 @@
+/* @flow */
+
+import VueI18n from './index'
+import { isPlainObject, warn, error, merge } from './util'
+
+export default {
+  beforeCreate (): void {
+    const options: any = this.$options
+    options.i18n = options.i18n || (options.__i18n ? {} : null)
+
+    if (options.i18n) {
+      if (options.i18n instanceof VueI18n) {
+        // init locale messages via custom blocks
+        if (options.__i18n) {
+          try {
+            let localeMessages = {}
+            options.__i18n.forEach(resource => {
+              localeMessages = merge(localeMessages, JSON.parse(resource))
+            })
+            Object.keys(localeMessages).forEach((locale: Locale) => {
+              options.i18n.mergeLocaleMessage(locale, localeMessages[locale])
+            })
+          } catch (e) {
+            if (process.env.NODE_ENV !== 'production') {
+              error(`Cannot parse locale messages via custom blocks.`, e)
+            }
+          }
+        }
+        this._i18n = options.i18n
+        this._i18nWatcher = this._i18n.watchI18nData()
+      } else if (isPlainObject(options.i18n)) {
+        const rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
+          ? this.$root.$i18n
+          : null
+        // component local i18n
+        if (rootI18n) {
+          options.i18n.root = this.$root
+          options.i18n.formatter = rootI18n.formatter
+          options.i18n.fallbackLocale = rootI18n.fallbackLocale
+          options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages
+          options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn
+          options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn
+          options.i18n.pluralizationRules = rootI18n.pluralizationRules
+          options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent
+        }
+
+        // init locale messages via custom blocks
+        if (options.__i18n) {
+          try {
+            let localeMessages = {}
+            options.__i18n.forEach(resource => {
+              localeMessages = merge(localeMessages, JSON.parse(resource))
+            })
+            options.i18n.messages = localeMessages
+          } catch (e) {
+            if (process.env.NODE_ENV !== 'production') {
+              warn(`Cannot parse locale messages via custom blocks.`, e)
+            }
+          }
+        }
+
+        const { sharedMessages } = options.i18n
+        if (sharedMessages && isPlainObject(sharedMessages)) {
+          options.i18n.messages = merge(options.i18n.messages, sharedMessages)
+        }
+
+        this._i18n = new VueI18n(options.i18n)
+        this._i18nWatcher = this._i18n.watchI18nData()
+
+        if (options.i18n.sync === undefined || !!options.i18n.sync) {
+          this._localeWatcher = this.$i18n.watchLocale()
+        }
+
+        if (rootI18n) {
+          rootI18n.onComponentInstanceCreated(this._i18n)
+        }
+      } else {
+        if (process.env.NODE_ENV !== 'production') {
+          warn(`Cannot be interpreted 'i18n' option.`)
+        }
+      }
+    } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+      // root i18n
+      this._i18n = this.$root.$i18n
+    } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+      // parent i18n
+      this._i18n = options.parent.$i18n
+    }
+  },
+
+  beforeMount (): void {
+    const options: any = this.$options
+    options.i18n = options.i18n || (options.__i18n ? {} : null)
+
+    if (options.i18n) {
+      if (options.i18n instanceof VueI18n) {
+        // init locale messages via custom blocks
+        this._i18n.subscribeDataChanging(this)
+        this._subscribing = true
+      } else if (isPlainObject(options.i18n)) {
+        this._i18n.subscribeDataChanging(this)
+        this._subscribing = true
+      } else {
+        if (process.env.NODE_ENV !== 'production') {
+          warn(`Cannot be interpreted 'i18n' option.`)
+        }
+      }
+    } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+      this._i18n.subscribeDataChanging(this)
+      this._subscribing = true
+    } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+      this._i18n.subscribeDataChanging(this)
+      this._subscribing = true
+    }
+  },
+
+  beforeDestroy (): void {
+    if (!this._i18n) { return }
+
+    const self = this
+    this.$nextTick(() => {
+      if (self._subscribing) {
+        self._i18n.unsubscribeDataChanging(self)
+        delete self._subscribing
+      }
+
+      if (self._i18nWatcher) {
+        self._i18nWatcher()
+        self._i18n.destroyVM()
+        delete self._i18nWatcher
+      }
+
+      if (self._localeWatcher) {
+        self._localeWatcher()
+        delete self._localeWatcher
+      }
+    })
+  }
+}

+ 302 - 0
plugin/vue-i18n/src/path.js

@@ -0,0 +1,302 @@
+/* @flow */
+
+import { isObject } from './util'
+
+/**
+ *  Path parser
+ *  - Inspired:
+ *    Vue.js Path parser
+ */
+
+// actions
+const APPEND = 0
+const PUSH = 1
+const INC_SUB_PATH_DEPTH = 2
+const PUSH_SUB_PATH = 3
+
+// states
+const BEFORE_PATH = 0
+const IN_PATH = 1
+const BEFORE_IDENT = 2
+const IN_IDENT = 3
+const IN_SUB_PATH = 4
+const IN_SINGLE_QUOTE = 5
+const IN_DOUBLE_QUOTE = 6
+const AFTER_PATH = 7
+const ERROR = 8
+
+const pathStateMachine: any = []
+
+pathStateMachine[BEFORE_PATH] = {
+  'ws': [BEFORE_PATH],
+  'ident': [IN_IDENT, APPEND],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+}
+
+pathStateMachine[IN_PATH] = {
+  'ws': [IN_PATH],
+  '.': [BEFORE_IDENT],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+}
+
+pathStateMachine[BEFORE_IDENT] = {
+  'ws': [BEFORE_IDENT],
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND]
+}
+
+pathStateMachine[IN_IDENT] = {
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND],
+  'ws': [IN_PATH, PUSH],
+  '.': [BEFORE_IDENT, PUSH],
+  '[': [IN_SUB_PATH, PUSH],
+  'eof': [AFTER_PATH, PUSH]
+}
+
+pathStateMachine[IN_SUB_PATH] = {
+  "'": [IN_SINGLE_QUOTE, APPEND],
+  '"': [IN_DOUBLE_QUOTE, APPEND],
+  '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
+  ']': [IN_PATH, PUSH_SUB_PATH],
+  'eof': ERROR,
+  'else': [IN_SUB_PATH, APPEND]
+}
+
+pathStateMachine[IN_SINGLE_QUOTE] = {
+  "'": [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_SINGLE_QUOTE, APPEND]
+}
+
+pathStateMachine[IN_DOUBLE_QUOTE] = {
+  '"': [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_DOUBLE_QUOTE, APPEND]
+}
+
+/**
+ * Check if an expression is a literal value.
+ */
+
+const literalValueRE: RegExp = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/
+function isLiteral (exp: string): boolean {
+  return literalValueRE.test(exp)
+}
+
+/**
+ * Strip quotes from a string
+ */
+
+function stripQuotes (str: string): string | boolean {
+  const a: number = str.charCodeAt(0)
+  const b: number = str.charCodeAt(str.length - 1)
+  return a === b && (a === 0x22 || a === 0x27)
+    ? str.slice(1, -1)
+    : str
+}
+
+/**
+ * Determine the type of a character in a keypath.
+ */
+
+function getPathCharType (ch: ?string): string {
+  if (ch === undefined || ch === null) { return 'eof' }
+
+  const code: number = ch.charCodeAt(0)
+
+  switch (code) {
+    case 0x5B: // [
+    case 0x5D: // ]
+    case 0x2E: // .
+    case 0x22: // "
+    case 0x27: // '
+      return ch
+
+    case 0x5F: // _
+    case 0x24: // $
+    case 0x2D: // -
+      return 'ident'
+
+    case 0x09: // Tab
+    case 0x0A: // Newline
+    case 0x0D: // Return
+    case 0xA0:  // No-break space
+    case 0xFEFF:  // Byte Order Mark
+    case 0x2028:  // Line Separator
+    case 0x2029:  // Paragraph Separator
+      return 'ws'
+  }
+
+  return 'ident'
+}
+
+/**
+ * Format a subPath, return its plain form if it is
+ * a literal string or number. Otherwise prepend the
+ * dynamic indicator (*).
+ */
+
+function formatSubPath (path: string): boolean | string {
+  const trimmed: string = path.trim()
+  // invalid leading 0
+  if (path.charAt(0) === '0' && isNaN(path)) { return false }
+
+  return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed
+}
+
+/**
+ * Parse a string path into an array of segments
+ */
+
+function parse (path: Path): ?Array<string> {
+  const keys: Array<string> = []
+  let index: number = -1
+  let mode: number = BEFORE_PATH
+  let subPathDepth: number = 0
+  let c: ?string
+  let key: any
+  let newChar: any
+  let type: string
+  let transition: number
+  let action: Function
+  let typeMap: any
+  const actions: Array<Function> = []
+
+  actions[PUSH] = function () {
+    if (key !== undefined) {
+      keys.push(key)
+      key = undefined
+    }
+  }
+
+  actions[APPEND] = function () {
+    if (key === undefined) {
+      key = newChar
+    } else {
+      key += newChar
+    }
+  }
+
+  actions[INC_SUB_PATH_DEPTH] = function () {
+    actions[APPEND]()
+    subPathDepth++
+  }
+
+  actions[PUSH_SUB_PATH] = function () {
+    if (subPathDepth > 0) {
+      subPathDepth--
+      mode = IN_SUB_PATH
+      actions[APPEND]()
+    } else {
+      subPathDepth = 0
+      if (key === undefined) { return false }
+      key = formatSubPath(key)
+      if (key === false) {
+        return false
+      } else {
+        actions[PUSH]()
+      }
+    }
+  }
+
+  function maybeUnescapeQuote (): ?boolean {
+    const nextChar: string = path[index + 1]
+    if ((mode === IN_SINGLE_QUOTE && nextChar === "'") ||
+      (mode === IN_DOUBLE_QUOTE && nextChar === '"')) {
+      index++
+      newChar = '\\' + nextChar
+      actions[APPEND]()
+      return true
+    }
+  }
+
+  while (mode !== null) {
+    index++
+    c = path[index]
+
+    if (c === '\\' && maybeUnescapeQuote()) {
+      continue
+    }
+
+    type = getPathCharType(c)
+    typeMap = pathStateMachine[mode]
+    transition = typeMap[type] || typeMap['else'] || ERROR
+
+    if (transition === ERROR) {
+      return // parse error
+    }
+
+    mode = transition[0]
+    action = actions[transition[1]]
+    if (action) {
+      newChar = transition[2]
+      newChar = newChar === undefined
+        ? c
+        : newChar
+      if (action() === false) {
+        return
+      }
+    }
+
+    if (mode === AFTER_PATH) {
+      return keys
+    }
+  }
+}
+
+export type PathValue = PathValueObject | PathValueArray | Function | string | number | boolean | null
+export type PathValueObject = { [key: string]: PathValue }
+export type PathValueArray = Array<PathValue>
+
+export default class I18nPath {
+  _cache: Object
+
+  constructor () {
+    this._cache = Object.create(null)
+  }
+
+  /**
+   * External parse that check for a cache hit first
+   */
+  parsePath (path: Path): Array<string> {
+    let hit: ?Array<string> = this._cache[path]
+    if (!hit) {
+      hit = parse(path)
+      if (hit) {
+        this._cache[path] = hit
+      }
+    }
+    return hit || []
+  }
+
+  /**
+   * Get path value from path string
+   */
+  getPathValue (obj: mixed, path: Path): PathValue {
+    if (!isObject(obj)) { return null }
+
+    const paths: Array<string> = this.parsePath(path)
+    if (paths.length === 0) {
+      return null
+    } else {
+      const length: number = paths.length
+      let last: any = obj
+      let i: number = 0
+      while (i < length) {
+        const value: any = last[paths[i]]
+        if (value === undefined) {
+          return null
+        }
+        last = value
+        i++
+      }
+
+      return last
+    }
+  }
+}

+ 169 - 0
plugin/vue-i18n/src/util.js

@@ -0,0 +1,169 @@
+/* @flow */
+
+/**
+ * constants
+ */
+
+export const numberFormatKeys = [
+  'style',
+  'currency',
+  'currencyDisplay',
+  'useGrouping',
+  'minimumIntegerDigits',
+  'minimumFractionDigits',
+  'maximumFractionDigits',
+  'minimumSignificantDigits',
+  'maximumSignificantDigits',
+  'localeMatcher',
+  'formatMatcher',
+  'unit'
+]
+
+/**
+ * utilities
+ */
+
+export function warn (msg: string, err: ?Error): void {
+  if (typeof console !== 'undefined') {
+    console.warn('[vue-i18n] ' + msg)
+    /* istanbul ignore if */
+    if (err) {
+      console.warn(err.stack)
+    }
+  }
+}
+
+export function error (msg: string, err: ?Error): void {
+  if (typeof console !== 'undefined') {
+    console.error('[vue-i18n] ' + msg)
+    /* istanbul ignore if */
+    if (err) {
+      console.error(err.stack)
+    }
+  }
+}
+
+export const isArray = Array.isArray
+
+export function isObject (obj: mixed): boolean %checks {
+  return obj !== null && typeof obj === 'object'
+}
+
+export function isBoolean (val: mixed): boolean %checks {
+  return typeof val === 'boolean'
+}
+
+export function isString (val: mixed): boolean %checks {
+  return typeof val === 'string'
+}
+
+const toString: Function = Object.prototype.toString
+const OBJECT_STRING: string = '[object Object]'
+export function isPlainObject (obj: any): boolean {
+  return toString.call(obj) === OBJECT_STRING
+}
+
+export function isNull (val: mixed): boolean {
+  return val === null || val === undefined
+}
+
+export function isFunction (val: mixed): boolean %checks {
+  return typeof val === 'function'
+}
+
+export function parseArgs (...args: Array<mixed>): Object {
+  let locale: ?string = null
+  let params: mixed = null
+  if (args.length === 1) {
+    if (isObject(args[0]) || isArray(args[0])) {
+      params = args[0]
+    } else if (typeof args[0] === 'string') {
+      locale = args[0]
+    }
+  } else if (args.length === 2) {
+    if (typeof args[0] === 'string') {
+      locale = args[0]
+    }
+    /* istanbul ignore if */
+    if (isObject(args[1]) || isArray(args[1])) {
+      params = args[1]
+    }
+  }
+
+  return { locale, params }
+}
+
+export function looseClone (obj: Object): Object {
+  return JSON.parse(JSON.stringify(obj))
+}
+
+export function remove (arr: Array<any>, item: any): Array<any> | void {
+  if (arr.length) {
+    const index = arr.indexOf(item)
+    if (index > -1) {
+      return arr.splice(index, 1)
+    }
+  }
+}
+
+export function includes (arr: Array<any>, item: any): boolean {
+  return !!~arr.indexOf(item)
+}
+
+const hasOwnProperty = Object.prototype.hasOwnProperty
+export function hasOwn (obj: Object | Array<*>, key: string): boolean {
+  return hasOwnProperty.call(obj, key)
+}
+
+export function merge (target: Object): Object {
+  const output = Object(target)
+  for (let i = 1; i < arguments.length; i++) {
+    const source = arguments[i]
+    if (source !== undefined && source !== null) {
+      let key
+      for (key in source) {
+        if (hasOwn(source, key)) {
+          if (isObject(source[key])) {
+            output[key] = merge(output[key], source[key])
+          } else {
+            output[key] = source[key]
+          }
+        }
+      }
+    }
+  }
+  return output
+}
+
+export function looseEqual (a: any, b: any): boolean {
+  if (a === b) { return true }
+  const isObjectA: boolean = isObject(a)
+  const isObjectB: boolean = isObject(b)
+  if (isObjectA && isObjectB) {
+    try {
+      const isArrayA: boolean = isArray(a)
+      const isArrayB: boolean = isArray(b)
+      if (isArrayA && isArrayB) {
+        return a.length === b.length && a.every((e: any, i: number): boolean => {
+          return looseEqual(e, b[i])
+        })
+      } else if (!isArrayA && !isArrayB) {
+        const keysA: Array<string> = Object.keys(a)
+        const keysB: Array<string> = Object.keys(b)
+        return keysA.length === keysB.length && keysA.every((key: string): boolean => {
+          return looseEqual(a[key], b[key])
+        })
+      } else {
+        /* istanbul ignore next */
+        return false
+      }
+    } catch (e) {
+      /* istanbul ignore next */
+      return false
+    }
+  } else if (!isObjectA && !isObjectB) {
+    return String(a) === String(b)
+  } else {
+    return false
+  }
+}

+ 276 - 0
plugin/vue-i18n/types/index.d.ts

@@ -0,0 +1,276 @@
+import Vue, { PluginFunction } from 'vue';
+
+declare namespace VueI18n {
+  type Path = string;
+  type Locale = string;
+  type FallbackLocale = string | string[] | false | { [locale: string]: string[] }
+  type Values = any[] | { [key: string]: any };
+  type Choice = number;
+  interface MessageContext {
+    list(index: number): unknown
+    named(key: string): unknown
+  }
+  type MessageFunction = (ctx: MessageContext) => string;
+  type LocaleMessage = string | MessageFunction | LocaleMessageObject | LocaleMessageArray;
+  interface LocaleMessageObject { [key: string]: LocaleMessage; }
+  interface LocaleMessageArray { [index: number]: LocaleMessage; }
+  interface LocaleMessages { [key: string]: LocaleMessageObject; }
+  type TranslateResult = string | LocaleMessages;
+
+  type LocaleMatcher = 'lookup' | 'best-fit';
+  type FormatMatcher = 'basic' | 'best-fit';
+
+  type DateTimeHumanReadable = 'long' | 'short' | 'narrow';
+  type DateTimeDigital = 'numeric' | '2-digit';
+
+  interface SpecificDateTimeFormatOptions extends Intl.DateTimeFormatOptions {
+    year?: DateTimeDigital;
+    month?: DateTimeDigital | DateTimeHumanReadable;
+    day?: DateTimeDigital;
+    hour?: DateTimeDigital;
+    minute?: DateTimeDigital;
+    second?: DateTimeDigital;
+    weekday?: DateTimeHumanReadable;
+    era?: DateTimeHumanReadable;
+    timeZoneName?: 'long' | 'short';
+    localeMatcher?: LocaleMatcher;
+    formatMatcher?: FormatMatcher;
+  }
+
+  type DateTimeFormatOptions = Intl.DateTimeFormatOptions | SpecificDateTimeFormatOptions;
+
+  interface DateTimeFormat { [key: string]: DateTimeFormatOptions; }
+  interface DateTimeFormats { [locale: string]: DateTimeFormat; }
+  type DateTimeFormatResult = string;
+
+  type CurrencyDisplay = 'symbol' | 'code' | 'name';
+
+  interface SpecificNumberFormatOptions extends Intl.NumberFormatOptions {
+    style?: 'decimal' | 'percent';
+    currency?: string;
+    currencyDisplay?: CurrencyDisplay;
+    localeMatcher?: LocaleMatcher;
+    formatMatcher?: FormatMatcher;
+  }
+
+  interface CurrencyNumberFormatOptions extends Intl.NumberFormatOptions {
+    style: 'currency';
+    currency: string; // Obligatory if style is 'currency'
+    currencyDisplay?: CurrencyDisplay;
+    localeMatcher?: LocaleMatcher;
+    formatMatcher?: FormatMatcher;
+  }
+
+  type NumberFormatOptions = Intl.NumberFormatOptions | SpecificNumberFormatOptions | CurrencyNumberFormatOptions;
+
+  interface NumberFormat { [key: string]: NumberFormatOptions; }
+  interface NumberFormats { [locale: string]: NumberFormat; }
+  type NumberFormatResult = string;
+  type PluralizationRulesMap = {
+    /**
+     * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
+     * @param choicesLength {number} an overall amount of available choices
+     * @returns a final choice index
+    */
+    [lang: string]: (choice: number, choicesLength: number) => number;
+  };
+  type Modifiers = { [key: string]: (str : string) => string };
+
+  type FormattedNumberPartType = 'currency' | 'decimal' | 'fraction' | 'group' | 'infinity' | 'integer' | 'literal' | 'minusSign' | 'nan' | 'plusSign' | 'percentSign';
+
+  type WarnHtmlInMessageLevel = 'off' | 'warn' | 'error';
+
+  interface FormattedNumberPart {
+    type: FormattedNumberPartType;
+    value: string;
+  }
+  interface NumberFormatToPartsResult { [index: number]: FormattedNumberPart; }
+
+  interface Formatter {
+    interpolate(message: string, values: Values | undefined, path: string): (any[] | null);
+  }
+
+  type MissingHandler = (locale: Locale, key: Path, vm: Vue | null, values: any) => string | void;
+  type PostTranslationHandler = (str: string, key?: string) => string;
+  type ComponentInstanceCreatedListener = (newVm: VueI18n & IVueI18n, rootVm: VueI18n & IVueI18n) => void;
+
+  interface IntlAvailability {
+    dateTimeFormat: boolean;
+    numberFormat: boolean;
+  }
+
+  // tslint:disable-next-line:interface-name
+  interface I18nOptions {
+    locale?: Locale;
+    fallbackLocale?: FallbackLocale;
+    messages?: LocaleMessages;
+    dateTimeFormats?: DateTimeFormats;
+    numberFormats?: NumberFormats;
+    formatter?: Formatter;
+    modifiers?: Modifiers,
+    missing?: MissingHandler;
+    fallbackRoot?: boolean;
+    formatFallbackMessages?: boolean;
+    sync?: boolean;
+    silentTranslationWarn?: boolean | RegExp;
+    silentFallbackWarn?: boolean | RegExp;
+    preserveDirectiveContent?: boolean;
+    pluralizationRules?: PluralizationRulesMap;
+    warnHtmlInMessage?: WarnHtmlInMessageLevel;
+    sharedMessages?: LocaleMessages;
+    postTranslation?: PostTranslationHandler;
+    componentInstanceCreatedListener?: ComponentInstanceCreatedListener;
+  }
+}
+
+export type Path = VueI18n.Path;
+export type Locale = VueI18n.Locale;
+export type FallbackLocale = VueI18n.FallbackLocale;
+export type Values = VueI18n.Values;
+export type Choice = VueI18n.Choice;
+export type MessageContext = VueI18n.MessageContext;
+export type MessageFunction = VueI18n.MessageFunction;
+export type LocaleMessage = VueI18n.LocaleMessage;
+export type LocaleMessageObject = VueI18n.LocaleMessageObject;
+export type LocaleMessageArray = VueI18n.LocaleMessageArray;
+export type LocaleMessages = VueI18n.LocaleMessages;
+export type TranslateResult = VueI18n.TranslateResult;
+export type DateTimeFormatOptions = VueI18n.DateTimeFormatOptions;
+export type DateTimeFormat = VueI18n.DateTimeFormat;
+export type DateTimeFormats = VueI18n.DateTimeFormats;
+export type DateTimeFormatResult = VueI18n.DateTimeFormatResult;
+export type NumberFormatOptions = VueI18n.NumberFormatOptions;
+export type NumberFormat = VueI18n.NumberFormat;
+export type NumberFormats = VueI18n.NumberFormats;
+export type NumberFormatResult = VueI18n.NumberFormatResult;
+export type NumberFormatToPartsResult = VueI18n.NumberFormatToPartsResult;
+export type WarnHtmlInMessageLevel = VueI18n.WarnHtmlInMessageLevel;
+export type Formatter = VueI18n.Formatter;
+export type MissingHandler = VueI18n.MissingHandler;
+export type PostTranslationHandler = VueI18n.PostTranslationHandler;
+export type IntlAvailability = VueI18n.IntlAvailability;
+export type I18nOptions = VueI18n.I18nOptions;
+
+export declare interface IVueI18n {
+  readonly messages: VueI18n.LocaleMessages;
+  readonly dateTimeFormats: VueI18n.DateTimeFormats;
+  readonly numberFormats: VueI18n.NumberFormats;
+
+  locale: VueI18n.Locale;
+  fallbackLocale: VueI18n.FallbackLocale;
+  missing: VueI18n.MissingHandler;
+  formatter: VueI18n.Formatter;
+  formatFallbackMessages: boolean;
+  silentTranslationWarn: boolean | RegExp;
+  silentFallbackWarn: boolean | RegExp;
+  preserveDirectiveContent: boolean;
+  pluralizationRules: VueI18n.PluralizationRulesMap;
+  warnHtmlInMessage: VueI18n.WarnHtmlInMessageLevel;
+  postTranslation: VueI18n.PostTranslationHandler;
+  t(key: VueI18n.Path, values?: VueI18n.Values): VueI18n.TranslateResult;
+  t(key: VueI18n.Path, locale: VueI18n.Locale, values?: VueI18n.Values): VueI18n.TranslateResult;
+  tc(key: VueI18n.Path, choice?: VueI18n.Choice, values?: VueI18n.Values): string;
+  tc(
+    key: VueI18n.Path,
+    choice: VueI18n.Choice,
+    locale: VueI18n.Locale,
+    values?: VueI18n.Values,
+  ): string;
+  te(key: VueI18n.Path, locale?: VueI18n.Locale): boolean;
+  d(
+    value: number | Date,
+    key?: VueI18n.Path,
+    locale?: VueI18n.Locale,
+  ): VueI18n.DateTimeFormatResult;
+  d(value: number | Date, args?: { [key: string]: string }): VueI18n.DateTimeFormatResult;
+  n(value: number, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
+  n(value: number, args?: { [key: string]: string }): VueI18n.NumberFormatResult;
+  getLocaleMessage(locale: VueI18n.Locale): VueI18n.LocaleMessageObject;
+  setLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
+  mergeLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
+  getDateTimeFormat(locale: VueI18n.Locale): VueI18n.DateTimeFormat;
+  setDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
+  mergeDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
+  getNumberFormat(locale: VueI18n.Locale): VueI18n.NumberFormat;
+  setNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
+  mergeNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
+  getChoiceIndex: (choice: number, choicesLength: number) => number;
+}
+
+declare class VueI18n {
+  constructor(options?: VueI18n.I18nOptions)
+
+  readonly messages: VueI18n.LocaleMessages;
+  readonly dateTimeFormats: VueI18n.DateTimeFormats;
+  readonly numberFormats: VueI18n.NumberFormats;
+  readonly availableLocales: VueI18n.Locale[];
+
+  locale: VueI18n.Locale;
+  fallbackLocale: VueI18n.FallbackLocale;
+  missing: VueI18n.MissingHandler;
+  formatter: VueI18n.Formatter;
+  formatFallbackMessages: boolean;
+  silentTranslationWarn: boolean | RegExp;
+  silentFallbackWarn: boolean | RegExp;
+  preserveDirectiveContent: boolean;
+  pluralizationRules: VueI18n.PluralizationRulesMap;
+  warnHtmlInMessage: VueI18n.WarnHtmlInMessageLevel;
+  postTranslation: VueI18n.PostTranslationHandler;
+
+  t(key: VueI18n.Path, values?: VueI18n.Values): VueI18n.TranslateResult;
+  t(key: VueI18n.Path, locale: VueI18n.Locale, values?: VueI18n.Values): VueI18n.TranslateResult;
+  tc(key: VueI18n.Path, choice?: VueI18n.Choice, values?: VueI18n.Values): string;
+  tc(key: VueI18n.Path, choice: VueI18n.Choice, locale: VueI18n.Locale, values?: VueI18n.Values): string;
+  te(key: VueI18n.Path, locale?: VueI18n.Locale): boolean;
+  d(value: number | Date, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.DateTimeFormatResult;
+  d(value: number | Date, args?: { [key: string]: string }): VueI18n.DateTimeFormatResult;
+  n(value: number, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
+  n(value: number, args?: { [key: string]: string }): VueI18n.NumberFormatResult;
+
+  getLocaleMessage(locale: VueI18n.Locale): VueI18n.LocaleMessageObject;
+  setLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
+  mergeLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
+
+  getDateTimeFormat(locale: VueI18n.Locale): VueI18n.DateTimeFormat;
+  setDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
+  mergeDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
+
+  getNumberFormat(locale: VueI18n.Locale): VueI18n.NumberFormat;
+  setNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
+  mergeNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
+
+  /**
+   * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
+   * @param choicesLength {number} an overall amount of available choices
+   * @returns a final choice index
+  */
+  getChoiceIndex: (choice: number, choicesLength: number) => number;
+
+  static install: PluginFunction<never>;
+  static version: string;
+  static availabilities: VueI18n.IntlAvailability;
+}
+
+declare module 'vue/types/vue' {
+  interface Vue {
+    readonly $i18n: VueI18n & IVueI18n;
+    $t: typeof VueI18n.prototype.t;
+    $tc: typeof VueI18n.prototype.tc;
+    $te: typeof VueI18n.prototype.te;
+    $d: typeof VueI18n.prototype.d;
+    $n: typeof VueI18n.prototype.n;
+  }
+}
+
+declare module 'vue/types/options' {
+  interface ComponentOptions<V extends Vue> {
+    i18n?: {
+      messages?: VueI18n.LocaleMessages;
+      dateTimeFormats?: VueI18n.DateTimeFormats;
+      numberFormats?: VueI18n.NumberFormats;
+      sharedMessages?: VueI18n.LocaleMessages;
+    };
+  }
+}
+
+export default VueI18n;

+ 34 - 0
plugin/vue-i18n/vetur/attributes.json

@@ -0,0 +1,34 @@
+{
+  "i18n/path" : {
+    "description": "[required]\nKeypath of the locale message",
+    "type": "string"
+  },
+  "i18n/locale" : {
+    "description": "[optional]\nLocale to be used in this translation",
+    "type": "string"
+  },
+  "i18n/tag" : {
+    "description": "[optional]\nWhich tag to render, default is \"span\"",
+    "type": "string"
+  },
+  "i18n/places": {
+    "description": "[optional after v8.14]\nWill be removed in the next major version, use the slot syntax instead\n\nhttp://kazupon.github.io/vue-i18n/guide/interpolation.html#slots-syntax-usage",
+    "type": "array|object"
+  },
+  "i18n-n/value" : {
+    "description": "[required]\nNumber to be used in formatting",
+    "type": "number"
+  },
+  "i18n-n/format": {
+    "description": "[optional]\nNumber format name or object with explicit format options",
+    "type": "string|object"
+  },
+  "i18n-n/locale" : {
+    "description": "[optional]\nLocale to be used in this translation",
+    "type": "string"
+  },
+  "i18n-n/tag" : {
+    "description": "[optional]\nWhich tag to render, default is `span`",
+    "type": "string"
+  }
+}

+ 20 - 0
plugin/vue-i18n/vetur/tags.json

@@ -0,0 +1,20 @@
+{
+  "i18n": {
+    "attributes": [
+      "path",
+      "locale",
+      "tag",
+      "places"
+    ],
+    "description": "This is a functional component that can be used when HTML interpolation is needed.\n\nhttp://kazupon.github.io/vue-i18n/guide/interpolation.html#basic-usage"
+  },
+  "i18n-n": {
+    "attributes": [
+      "value",
+      "format",
+      "locale",
+      "tag"
+    ],
+    "description": "This functional component provides a way to use HTML interpolation in pair with number formatting.\n\nhttp://kazupon.github.io/vue-i18n/guide/number.html#custom-formatting"
+  }
+}

+ 551 - 0
static/css/cmy.css

@@ -0,0 +1,551 @@
+/*初始化类*/
+@font-face {
+	font-family: 'iconfont';
+	/* project id 1482221 */
+	src: url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.eot');
+	src: url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.eot?#iefix') format('embedded-opentype'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.woff2') format('woff2'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.woff') format('woff'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.ttf') format('truetype'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.svg#iconfont') format('svg');
+}
+
+.acea-row {
+	display: -webkit-box;
+	display: -moz-box;
+	display: -webkit-flex;
+	display: -ms-flexbox;
+	display: flex;
+	-webkit-box-lines: multiple;
+	-moz-box-lines: multiple;
+	-o-box-lines: multiple;
+	-webkit-flex-wrap: wrap;
+	-ms-flex-wrap: wrap;
+	flex-wrap: wrap
+}
+
+.acea-row.row-middle {
+	-webkit-box-align: center;
+	-moz-box-align: center;
+	-o-box-align: center;
+	-ms-flex-align: center;
+	-webkit-align-items: center;
+	align-items: center
+}
+
+.bg-color-red {
+	background-color: #e93323 !important;
+}
+
+.acea-row.row-right {
+	-webkit-box-pack: end;
+	-moz-box-pack: end;
+	-o-box-pack: end;
+	-ms-flex-pack: end;
+	-webkit-justify-content: flex-end;
+	justify-content: flex-end
+}
+
+.acea-row.row-between-wrapper {
+	-webkit-box-align: center;
+	-moz-box-align: center;
+	-o-box-align: center;
+	-ms-flex-align: center;
+	-webkit-align-items: center;
+	align-items: center;
+	-webkit-box-pack: justify;
+	-moz-box-pack: justify;
+	-o-box-pack: justify;
+	-ms-flex-pack: justify;
+	-webkit-justify-content: space-between;
+	justify-content: space-between
+}
+
+.acea-row.row-column-around {
+	-webkit-flex-direction: column;
+	-ms-flex-direction: column;
+	flex-direction: column;
+	justify-content: space-around;
+	-webkit-justify-content: space-around
+}
+
+.acea-row.row-center-wrapper {
+	-webkit-box-align: center;
+	-moz-box-align: center;
+	-o-box-align: center;
+	-ms-flex-align: center;
+	-webkit-align-items: center;
+	align-items: center;
+	-webkit-box-pack: center;
+	-moz-box-pack: center;
+	-o-box-pack: center;
+	-ms-flex-pack: center;
+	-webkit-justify-content: center;
+	justify-content: center
+}
+
+.iconfont {
+	font-family: "iconfont" !important;
+	font-size: 34rpx;
+	font-style: normal;
+	-webkit-font-smoothing: antialiased;
+	-webkit-text-stroke-width: 0rpx;
+	-moz-osx-font-smoothing: grayscale;
+}
+
+.iconedit:before {
+	content: "\e649";
+}
+
+.iconfavorfill:before {
+	content: "\e64b";
+}
+
+.iconfavor:before {
+	content: "\e64c";
+}
+
+.iconlocation:before {
+	content: "\e651";
+}
+
+.iconroundcheckfill:before {
+	content: "\e656";
+}
+
+.iconroundcheck:before {
+	content: "\e657";
+}
+
+.iconunfold:before {
+	content: "\e661";
+}
+
+.iconlikefill:before {
+	content: "\e668";
+}
+
+.iconlike:before {
+	content: "\e669";
+}
+
+.iconshop:before {
+	content: "\e676";
+}
+
+.iconcart:before {
+	content: "\e6af";
+}
+
+.icondelete:before {
+	content: "\e6b4";
+}
+
+.iconhome:before {
+	content: "\e6b8";
+}
+
+.iconcartfill:before {
+	content: "\e6b9";
+}
+
+.iconhomefill:before {
+	content: "\e6bb";
+}
+
+.iconlock:before {
+	content: "\e6c0";
+}
+
+.iconfriendadd:before {
+	content: "\e6ca";
+}
+
+.iconfold:before {
+	content: "\e6de";
+}
+
+.iconapps:before {
+	content: "\e729";
+}
+
+.iconadd:before {
+	content: "\e767";
+}
+
+.iconmove:before {
+	content: "\e768";
+}
+
+.icontriangledownfill:before {
+	content: "\e79b";
+}
+
+.icontriangleupfill:before {
+	content: "\e79c";
+}
+
+.iconshaixuan:before {
+	content: "\e74a";
+}
+
+.iconyanzhengma:before {
+	content: "\e684";
+}
+
+.iconjifen:before {
+	content: "\e60f";
+}
+
+.iconwuliuxinxi:before {
+	content: "\e62b";
+}
+
+.iconmessage:before {
+	content: "\e78a";
+}
+
+.iconsetting:before {
+	content: "\e78e";
+}
+
+.iconaddition:before {
+	content: "\e6e0";
+}
+
+.iconclose:before {
+	content: "\e6e9";
+}
+
+.iconenter:after {
+	content: "\e6f8";
+}
+
+.iconprompt:before {
+	content: "\e71b";
+}
+
+.iconreturn:before {
+	content: "\e720";
+}
+
+.iconsearch:before {
+	content: "\e741";
+}
+
+.iconpengyouquan:before {
+	content: "\e62c";
+}
+
+.iconweixin:before {
+	content: "\e60e";
+}
+
+.iconzhifubao:before {
+	content: "\e673";
+}
+
+.iconyue:before {
+	content: "\e618";
+}
+
+.iconweixin1:before {
+	content: "\e622";
+}
+
+.iconlock1:before {
+	content: "\e64d";
+}
+
+.iconuser:before {
+	content: "\e64e";
+}
+
+.iconchenggongtixianshouyi:before {
+	content: "\e64f";
+}
+
+.iconviptuiguangdingdan:before {
+	content: "\e650";
+}
+
+.icondaifukuan:before {
+	content: "\e652";
+}
+
+.icondaijiesuanshouyi:before {
+	content: "\e653";
+}
+
+.icondaidakuanshouyi:before {
+	content: "\e654";
+}
+
+.icondaifahuo:before {
+	content: "\e655";
+}
+
+.icondaishouhuoshouyi:before {
+	content: "\e658";
+}
+
+.icondaishouhuo:before {
+	content: "\e659";
+}
+
+.iconwuxiaoshouyi:before {
+	content: "\e65a";
+}
+
+.icontixianmingxi:before {
+	content: "\e65b";
+}
+
+.iconshouyi:before {
+	content: "\e65c";
+}
+
+.iconkouchutixianshouxufei:before {
+	content: "\e65d";
+}
+
+.iconyishenqingshouyi:before {
+	content: "\e65e";
+}
+
+.icontuihuanhuo:before {
+	content: "\e65f";
+}
+
+
+/*水平线*/
+.hr {
+	width: 100%;
+	position: relative;
+	border-bottom: 1px solid #dddddd;
+	/* height: 0.5rpx; */
+}
+
+/* 一行显示 */
+.clamp {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	display: block;
+}
+
+/* 二行显示 */
+.clamp2 {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-line-clamp: 2;
+	-webkit-box-orient: vertical;
+}
+
+/* 二行显示 */
+.ellipsis {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-box-orient: vertical;
+	-webkit-line-clamp: 2;
+}
+
+.common-hover {
+	background: #f5f5f5;
+}
+
+/* 角标 */
+.corner {
+	background-color: #e51c23;
+	position: absolute;
+	right: -18rpx;
+	top: -18rpx;
+	color: #FFFFFF;
+	text-align: center;
+	border-radius: 999px;
+	font-size: 24rpx !important;
+	min-width: 35rpx;
+	min-height: 35rpx;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	line-height: 1;
+}
+
+.flex_item {
+	display: flex;
+	align-items: center;
+	/* justify-content: space-between; */
+}
+
+/* 左右顶格加上下居中 */
+.flex-between-center {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+}
+
+/* flex布局-整体居中 */
+.flex-center {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.flex-start {
+	display: flex;
+	align-items: center;
+	justify-content: flex-start;
+}
+
+/*文字对齐*/
+.text-left {
+	text-align: left !important;
+}
+
+.text-center {
+	text-align: center !important;
+}
+
+.text-justify {
+	text-align: justify !important;
+}
+
+.text-right {
+	text-align: right !important;
+}
+
+.text-default {
+	color: #212121 !important;
+}
+
+.text-white {
+	color: #ffffff !important;
+}
+
+.text-primary {
+	color: #00bcd4 !important;
+}
+
+.text-success {
+	color: #009688 !important;
+}
+
+.text-info {
+	color: #03a9f4 !important;
+}
+
+.text-warning {
+	color: #ffc107 !important;
+}
+
+.text-danger {
+	color: #e51c23 !important;
+}
+
+.text-pink {
+	color: #e91e63 !important;
+}
+
+.text-purple {
+	color: #673ab7 !important;
+}
+
+.text-indigo {
+	color: #3f51b5 !important;
+}
+
+.text-gray {
+	color: #999999 !important;
+}
+
+.bg-default {
+	background-color: #f5f5f5 !important;
+}
+
+.bg-primary {
+	background-color: #00bcd4 !important;
+}
+
+.bg-success {
+	background-color: #009688 !important;
+}
+
+.bg-info {
+	background-color: #03a9f4 !important;
+}
+
+.bg-warning {
+	background-color: #FFB238 !important;
+}
+
+.bg-danger {
+	background-color: #DC4D46 !important;
+}
+
+.bg-pink {
+	background-color: #e91e63 !important;
+}
+
+.bg-purple {
+	background-color: #673ab7 !important;
+}
+
+.bg-indigo {
+	background-color: #3f51b5 !important;
+}
+
+.bg-white {
+	background-color: white !important;
+}
+
+.bg-gray {
+	background-color: #e3e3e3 !important;
+}
+
+/* 边框 */
+.border-radius-15 {
+	border-radius: 15rpx;
+}
+
+.border-radius-10 {
+	border-radius: 10rpx;
+}
+
+.border-radius-all {
+	border-radius: 1000rpx;
+}
+
+/* 底部边线 */
+.borde-b {
+	border-bottom: 1px solid #dddddd;
+}
+
+/* 弹性盒子 */
+.flex {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+}
+
+.items-left {
+	justify-content: flex-start;
+}
+
+.items-right {
+	justify-content: flex-end;
+}
+
+.flex-shrink-false {
+	flex-shrink: 0;
+}
+
+.flex-grow-true {
+	flex-grow: 1;
+}
+
+.position-relative {
+	position: relative;
+}

BIN
static/error/emptyCart.png


BIN
static/error/errorImage.jpg


BIN
static/error/missing-face.png


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