Commit a3e12871 authored by 杨硕's avatar 杨硕

初始化

parents
unpackage/
.hbuilderx/
\ No newline at end of file
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/linjiashop-uniapp.iml" filepath="$PROJECT_DIR$/.idea/linjiashop-uniapp.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
<script>
export default {
// 此处globalData为了演示其作用,不是uView框架的一部分
globalData: {
username: ''
},
onLaunch() {
// 1.1.0版本之前关于http拦截器代码,已平滑移动到/common/http.interceptor.js中
// 注意,需要在/main.js中实例化Vue之后引入如下(详见文档说明):
// import httpInterceptor from '@/common/http.interceptor.js'
// Vue.use(httpInterceptor, app)
},
}
</script>
<style lang="scss">
@import "uview-ui/index.scss";
@import "common/demo.scss";
/*每个页面公共css */
</style>
\ No newline at end of file
MIT License
Copyright (c) 2020 www.uviewui.com
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.
\ No newline at end of file
<p align="center">
<img alt="logo" src="http://microapp.gitee.io/linjiashop/logo.jpg" width="120" height="120" style="margin-bottom: 10px;">
</p>
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">linjiashop-uniapp</h3>
<h3 align="center">邻家小铺uniapp(全平台)版本</h3>
## 前言
- linjiashop-uniapp,是[邻家小铺](http://microapp.gitee.io/linjiashop/)的uniapp版本,通过uniapp技术达到一套代码覆盖全平台(H5,Android,IOS,微信小程序,其他如支付宝,qq,头条小程序也可以通过简单的适配实现)的目的
- 项目地址[gitee](https://gitee.com/microapp/linjiashop-uniapp),[github](https://github.com/microapp-store/linjiashop-uniapp)
- [官方文档:http://microapp.gitee.io/linjiashop/](http://microapp.gitee.io/linjiashop/ecosystem/uniapp.html)
- linjiashop-uniapp使用了[uView组件](https://www.uviewui.com)作为前端框架,开发过程可以多看其官方文档
- 加群交流反馈:909904351
## 演示
- H5:[http://linjiashop.microapp.store/](http://linjiashop.microapp.store/) 浏览器打开后通过F12打开控制台使用手机模式查看
- App:[http://fir.microapp.store/linjiashop](http://fir.microapp.store/linjiashop)
- 微信小程序:请自己用微信开发工具预览
## 快速开始
- 克隆本项目 git clone https://gitee.com/microapp/linjiashop-uniapp.git
- 使用Hbuilder X 开发工具打开本项目进行开发(本项目开发使用开发工具的2.7.14版本,为避免出现不必要的问题,建议使用开发工具不要低于本版本)
- 具体开发过程请参考uniapp[官方文档](https://uniapp.dcloud.io/)和uView的[官方文档](https://www.uviewui.com/)
## 友情链接
#### **linjiashop** —— [基于SpringBoot和Vue.js的轻量级小商城](http://microapp.gitee.io/linjiashop/)
#### **linjiashop-flutter** —— [邻家小铺的flutter版本](https://gitee.com/microapp/linjiashop-flutter)
#### **web-flash** —— [基于SpringBoot和Vue.js 后台管理脚手架](https://enilu.gitee.io/web-flash/)
#### **material-admin** —— [web-flash的单体版本(相对于web-flash的前后端分离版本)](https://enilu.gitee.io/material-admin/)
<br>
## 版权信息
本项目遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将linjiashop-uniapp应用到您的产品中。
// config.js,根目录的common文件夹中
export default {
// baseApi: 'http://linjiashop.microapp.store/prod-api' //调用演示环境
// baseApi:'/prod-api'//web生产
baseApi: 'https://qf.91isoft.com/cshop'//本地测试
}
/* #ifndef APP-NVUE */
view,
text {
box-sizing: border-box;
}
/* #endif */
/* start--演示页面使用的统一样式--start */
.u-demo {
padding: 50rpx 40rpx;
}
.u-demo-wrap {
border-width: 1px;
border-color: #ddd;
border-style: dashed;
background-color: rgb(250, 250, 250);
padding: 40rpx 20rpx;
border-radius: 6px;
}
.u-demo-area {
text-align: center;
}
.u-no-demo-here {
color: $u-tips-color;
font-size: 26rpx;
}
.u-demo-result-line {
border-width: 1px;
border-color: #ddd;
border-style: dashed;
padding: 10rpx 40rpx;
margin-top: 30rpx;
border-radius: 5px;
background-color: rgb(240, 240, 240);
color: $u-content-color;
font-size: 32rpx;
/* #ifndef APP-NVUE */
word-break: break-word;
display: inline-block;
/* #endif */
text-align: left;
}
.u-demo-title,
.u-config-title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
margin-bottom: 40rpx;
}
.u-config-item {
margin-top: 50rpx;
}
.u-config-title {
margin-top: 40rpx;
padding-bottom: 10rpx;
}
.u-item-title {
position: relative;
font-size: 28rpx;
padding-left: 8px;
line-height: 1;
margin-bottom: 22rpx;
}
.u-item-title:after {
position: absolute;
width: 4px;
top: -1px;
height: 16px;
/* #ifndef APP-NVUE */
content: '';
/* #endif */
left: 0;
border-radius: 10px;
background-color: $u-content-color;
}
/* end--演示页面使用的统一样式--end */
// 如果没有通过拦截器配置域名的话,可以在这里写上完整的URL(加上域名部分)
let hotSearchUrl = '/ebapi/store_api/hot_search';
let indexUrl = '/ebapi/public_api/index';
let sendSmsCodeUrl = 'sendSmsCode';
// 此处第二个参数vm,就是我们在页面使用的this,你可以通过vm获取vuex等操作,更多内容详见uView对拦截器的介绍部分:
// https://uviewui.com/js/http.html#%E4%BD%95%E8%B0%93%E8%AF%B7%E6%B1%82%E6%8B%A6%E6%88%AA%EF%BC%9F
const install = (Vue, vm) => {
// 此处没有使用传入的params参数
let getSearch = (params = {}) => vm.$u.get(hotSearchUrl, {
id: 2
});
// 此处使用了传入的params参数,一切自定义即可
let getInfo = (params = {}) => vm.$u.post(indexUrl, params);
let sendSmsCode = (params = {}) => vm.$u.get(sendSmsCodeUrl, params);
// 将各个定义的接口名称,统一放进对象挂载到vm.$u.api(因为vm就是this,也即this.$u.api)下
vm.$u.api = {getSearch, getInfo,sendSmsCode};
}
export default {
install
}
\ No newline at end of file
// 这里的vm,就是我们在vue文件里面的this,所以我们能在这里获取vuex的变量,比如存放在里面的token
// 同时,我们也可以在此使用getApp().globalData,如果你把token放在getApp().globalData的话,也是可以使用的
import config from "./config"
const install = (Vue, vm) => {
Vue.prototype.$u.http.setConfig({
baseUrl: config.baseApi,
showLoading: true, // 是否显示请求中的loading
loadingText: '请求中...', // 请求loading中的文字提示
loadingTime: 1000, // 在此时间内,请求还没回来的话,就显示加载中动画,单位ms
originalData: false, // 是否在拦截器中返回服务端的原始数据
loadingMask: true, // 展示loading的时候,是否给一个透明的蒙层,防止触摸穿透
// 如果将此值设置为true,拦截回调中将会返回服务端返回的所有数据response,而不是response.data
// 设置为true后,就需要在this.$u.http.interceptor.response进行多一次的判断,请打印查看具体值
// originalData: true,
// 设置自定义头部content-type
// header: {
// 'content-type': 'xxx'
// }
});
// 请求拦截,配置Token等参数
Vue.prototype.$u.http.interceptor.request = (config) => {
console.log("request",config);
// config.header.Token = 'xxxxxx';
// 方式一,存放在vuex的token,假设使用了uView封装的vuex方式,见:https://uviewui.com/components/globalVariable.html
config.header.Authorization = vm.vuex_token;
// 方式二,如果没有使用uView封装的vuex方法,那么需要使用$store.state获取
// config.header.token = vm.$store.state.token;
// 方式三,如果token放在了globalData,通过getApp().globalData获取
// config.header.token = getApp().globalData.username;
// 方式四,如果token放在了Storage本地存储中,拦截是每次请求都执行的,所以哪怕您重新登录修改了Storage,下一次的请求将会是最新值
// const token = uni.getStorageSync('token');
// config.header.token = token;
return config;
}
// 响应拦截,判断状态码是否通过
Vue.prototype.$u.http.interceptor.response = (res) => {
// 如果把originalData设置为了true,这里得到将会是服务器返回的所有的原始数据
// 判断可能变成了res.statueCode,或者res.data.code之类的,请打印查看结果
if (res.code == 20000) {
// 如果把originalData设置为了true,这里return回什么,this.$u.post的then回调中就会得到什么
return res.data;
} else {
//todo 统一处理错误信息
if(res.msg){
Vue.prototype.$u.toast(res.msg);
return false;
}
return false;
}
}
//异常统一处理
Vue.prototype.$u.http.interceptor.error = (res) => {
console.log('error',res);
if(res.statusCode == 401){
//跳转至登录页面
Vue.prototype.$u.route('/pages/login/login');
return true;
}else{
if(res.data.message){
Vue.prototype.$u.toast(res.data.message);
return false;
}
}
return false;
}
}
export default {
install
}
This diff is collapsed.
export default {
// 可以以页面为单位来写,比如首页的内容,写在index字段,个人中心写在center,共同部分写在common部分
components: {
desc: 'Numerous components cover the various requirements of the development process, and the components are rich in functions and compatible with multiple terminals. Let you integrate quickly, out of the box'
},
js: {
desc: 'Numerous intimate gadgets are a weapon that you can call upon during the development process, allowing you to dart in your hand and pierce the Yang with a hundred steps'
},
template: {
desc: 'Collection of many commonly used pages and layouts, reducing the repetitive work of developers, allowing you to focus on logic and get twice the result with half the effort'
},
nav: {
components: 'Comonents',
js: 'JS',
template: 'Template'
},
common: {
intro: '轻量简洁的商城系统',
title: '邻家小铺',
},
}
\ No newline at end of file
export default {
// 可以以页面为单位来写,比如首页的内容,写在index字段,个人中心写在center,共同部分写在common部分
components: {
desc: '众多组件覆盖开发过程的各个需求,组件功能丰富,多端兼容。让你快速集成,开箱即用'
},
js: {
desc: '众多的贴心小工具,是你开发过程中召之即来的利器,让你飞镖在手,百步穿杨'
},
template: {
desc: '收集众多的常用页面和布局,减少开发者的重复工作,让你专注逻辑,事半功倍'
},
nav: {
components: '组件',
js: '工具',
template: '模板'
},
common: {
intro: '轻量简洁的商城系统',
title: '邻家小铺',
},
}
\ No newline at end of file
function maskMobile(mobile) {
if (mobile.length == 11) {
const ret = mobile.substring(0,3) + '****' + mobile.substring(7)
return ret
}
return mobile.substring(0,3)+'********'
}
module.exports = {
maskMobile:maskMobile
}
This diff is collapsed.
This diff is collapsed.
<template>
<view class="nav-wrap">
<view class="nav-title">
<image class="logo" src="https://cdn.uviewui.com/uview/common/logo.png" mode="widthFix"></image>
<view class="nav-info">
<view class="nav-title__text">
{{$t('common.title')}}
</view>
<view class="nav-slogan">
{{$t('common.intro')}}
</view>
</view>
</view>
<view class="nav-desc">
{{desc}}
</view>
<view class="lang" @tap="switchLang">
<u-icon size="46" color="warning" :name="lang"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
desc: String,
title: String,
},
computed: {
lang() {
return this.$i18n.locale == 'zh' ? 'zh' : 'en';
}
},
methods: {
switchLang() {
this.$i18n.locale = this.$i18n.locale == 'en' ? 'zh' : 'en';
this.vuex_tabbar[0].text = this.$t('nav.components')
this.vuex_tabbar[1].text = this.$t('nav.js')
this.vuex_tabbar[2].text = this.$t('nav.template')
uni.setNavigationBarTitle({
title: this.$t(this.title)
});
}
}
}
</script>
<style lang="scss" scoped>
.nav-wrap {
padding: 30rpx;
position: relative;
}
.lang {
position: absolute;
top: 30rpx;
right: 30rpx;
}
.nav-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
}
.nav-info {
margin-left: 30rpx;
}
.nav-title__text {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
color: $u-main-color;
font-size: 50rpx;
font-weight: bold;
}
.logo {
width: 140rpx;
/* #ifndef APP-NVUE */
height: auto;
/* #endif */
}
.nav-slogan {
color: $u-tips-color;
font-size: 28rpx;
}
.nav-desc {
margin-top: 20rpx;
font-size: 28rpx;
color: $u-content-color;
}
</style>
File added
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
App.mpType = 'app'
// 此处为演示Vue.prototype使用,非uView的功能部分
Vue.prototype.vuePrototype = '枣红'
// 引入全局uView
import uView from 'uview-ui'
Vue.use(uView)
// 此处为演示vuex使用,非uView的功能部分
import store from '@/store'
// 引入uView提供的对vuex的简写法文件
let vuexStore = require('@/store/$u.mixin.js')
Vue.mixin(vuexStore)
// 引入uView对小程序分享的mixin封装
let mpShare = require('uview-ui/libs/mixin/mpShare.js');
Vue.mixin(mpShare)
// weixin
// import wx from '@/common/weixin-js-sdk.js'
// weixin
// Vue.use(wx)
// i18n部分的配置
// 引入语言包,注意路径
import Chinese from '@/common/locales/zh.js';
import English from '@/common/locales/en.js';
// VueI18n
import VueI18n from '@/common/vue-i18n.min.js'
// VueI18n
Vue.use(VueI18n)
const i18n = new VueI18n({
// 默认语言
locale: 'zh',
// 引入语言文件
messages: {
'zh': Chinese,
'en': English,
}
})
// 由于微信小程序的运行机制问题,需声明如下一行,H5和APP非必填
Vue.prototype._i18n = i18n
const app = new Vue({
i18n,
store,
...App
})
// http拦截器,将此部分放在new Vue()和app.$mount()之间,才能App.vue中正常使用
import httpInterceptor from '@/common/http.interceptor.js'
Vue.use(httpInterceptor, app)
// http接口API抽离,免于写url或者一些固定的参数
import httpApi from '@/common/http.api.js'
Vue.use(httpApi, app)
import config from "@/common/config.js"
Vue.prototype.baseApi = config.baseApi;
app.$mount()
{
"name" : "邻家小铺",
"appid" : "__UNI__4ED93C0",
"description" : "轻量、简介的开源小商城系统",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
"app-plus" : {
// APP-VUE分包,可提APP升启动速度,2.7.12开始支持,兼容微信小程序分包方案,默认关闭
"optimization" : {
"subPackages" : true
},
"safearea" : {
"bottom" : {
"offset" : "none"
}
},
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"compilerVersion" : 3,
"modules" : {
"Payment" : {}
},
"distribute" : {
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a" ]
},
"ios" : {},
"sdkConfigs" : {
"ad" : {},
"payment" : {
"weixin" : {
"__platform__" : [ "android" ],
"appid" : "wx1b39ed76db874344",
"UniversalLinks" : ""
}
}
},
"icons" : {
"android" : {
"hdpi" : "",
"xhdpi" : "",
"xxhdpi" : "",
"xxxhdpi" : ""
},
"ios" : {
"appstore" : "",
"ipad" : {
"app" : "",
"app@2x" : "",
"notification" : "",
"notification@2x" : "",
"proapp@2x" : "",
"settings" : "",
"settings@2x" : "",
"spotlight" : "",
"spotlight@2x" : ""
},
"iphone" : {
"app@2x" : "",
"app@3x" : "",
"notification@2x" : "",
"notification@3x" : "",
"settings@2x" : "",
"settings@3x" : "",
"spotlight@2x" : "",
"spotlight@3x" : ""
}
}
}
}
},
"quickapp" : {},
"mp-weixin" : {
"appid" : "wx16cfb2d12e4ab57c",
"setting" : {
"urlCheck" : true,
"es6" : true,
"minified" : true,
"postcss" : true
},
"optimization" : {
"subPackages" : true
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true,
"component2" : true
},
"mp-qq" : {
"optimization" : {
"subPackages" : true
},
"appid" : ""
},
"mp-baidu" : {
"usingComponents" : true,
"appid" : ""
},
"mp-toutiao" : {
"usingComponents" : true,
"appid" : ""
},
"h5" : {
"template" : "template.h5.html",
"router" : {
"mode" : "hash",
"base" : ""
},
"optimization" : {
"treeShaking" : {
"enable" : false
}
},
"title" : "邻家小铺"
}
}
This diff is collapsed.
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.
<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)
declare var Intl: any;
declare type Path = string;
declare type Locale = string;
declare type FallbackLocale = string | string[] | false | { [locale: string]: string[] };
declare type LocaleMessage = string | 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)
};
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,
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"_from": "vue-i18n",
"_id": "vue-i18n@8.20.0",
"_inBundle": false,
"_integrity": "sha512-ZiAOoeR4d/JtKpbjipx3I80ey7cYG1ki5gQ7HwzWm4YFio9brA15BEYHjalEoBaEfzF5OBEZP+Y2MvAaWnyXXg==",
"_location": "/vue-i18n",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "vue-i18n",
"name": "vue-i18n",
"escapedName": "vue-i18n",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.20.0.tgz",
"_shasum": "c81b01d6541182b28565316cafe881b65a3c0f1b",
"_spec": "vue-i18n",
"_where": "E:\\www\\uniapp\\uView",
"author": {
"name": "kazuya kawaguchi",
"email": "kawakazu80@gmail.com"
},
"bugs": {
"url": "https://github.com/kazupon/vue-i18n/issues"
},
"bundleDependencies": false,
"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"
}
},
"deprecated": false,
"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.20.0",
"vetur": {
"tags": "vetur/tags.json",
"attributes": "vetur/attributes.json"
}
}
/* @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)
}
/* @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
}
}
/* @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
}
/* @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)
}
}
/* @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
}
This diff is collapsed.
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
}
}
/* @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
}
})
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"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"
}
}
{
"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"
}
}
{
"name": "uView",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"vue-i18n": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.20.0.tgz",
"integrity": "sha512-ZiAOoeR4d/JtKpbjipx3I80ey7cYG1ki5gQ7HwzWm4YFio9brA15BEYHjalEoBaEfzF5OBEZP+Y2MvAaWnyXXg=="
}
}
}
{
"name": "邻家小铺",
"version": "1.0.0",
"description": "<p align=\"center\">\r <img alt=\"logo\" src=\"https://uviewui.com/common/logo.png\" width=\"120\" height=\"120\" style=\"margin-bottom: 10px;\">\r </p>\r <h3 align=\"center\" style=\"margin: 30px 0 30px;font-weight: bold;font-size:40px;\">uView</h3>\r <h3 align=\"center\">多平台快速开发的UI框架</h3>",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/YanxinNet/uView.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/YanxinNet/uView/issues"
},
"homepage": "https://github.com/YanxinNet/uView#readme",
"dependencies": {
"vue-i18n": "^8.20.0"
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<template>
<view class="u-demo">
<view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view>
<view class="u-demo-area">
<view class="u-no-demo-here">
只对各家小程序有效,点击右上角的"胶囊",即可弹出分享菜单
</view>
</view>
</view>
</view>
</template>
<script>
</script>
<style lang="scss" scoped>
.u-demo {}
</style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment