Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
yangkaifeng
uni-app
提交
9dc717e3
U
uni-app
项目概览
yangkaifeng
/
uni-app
与 Fork 源项目一致
Fork自
DCloud / uni-app
通知
3
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
9dc717e3
编写于
8月 31, 2021
作者:
fxy060608
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
wip(i18n): json i18n
上级
073d3134
变更
32
隐藏空白更改
内联
并排
Showing
32 changed file
with
996 addition
and
152 deletion
+996
-152
packages/shims-uni-app.d.ts
packages/shims-uni-app.d.ts
+1
-0
packages/uni-app-plus/dist/uni-app-service.es.js
packages/uni-app-plus/dist/uni-app-service.es.js
+74
-34
packages/uni-app-plus/dist/uni-app-view.umd.js
packages/uni-app-plus/dist/uni-app-view.umd.js
+1
-1
packages/uni-app-plus/src/service/framework/amd/index.ts
packages/uni-app-plus/src/service/framework/amd/index.ts
+7
-3
packages/uni-app-vite/src/plugin/uni/index.ts
packages/uni-app-vite/src/plugin/uni/index.ts
+24
-5
packages/uni-cli-shared/__tests__/i18n.spec.ts
packages/uni-cli-shared/__tests__/i18n.spec.ts
+18
-0
packages/uni-cli-shared/src/i18n.ts
packages/uni-cli-shared/src/i18n.ts
+48
-0
packages/uni-cli-shared/src/index.ts
packages/uni-cli-shared/src/index.ts
+1
-0
packages/uni-cli-shared/src/json/app/manifest/merge.ts
packages/uni-cli-shared/src/json/app/manifest/merge.ts
+24
-1
packages/uni-cli-shared/src/json/manifest.ts
packages/uni-cli-shared/src/json/manifest.ts
+5
-0
packages/uni-cli-shared/src/messages/index.ts
packages/uni-cli-shared/src/messages/index.ts
+4
-0
packages/uni-cli-shared/src/vite/features.ts
packages/uni-cli-shared/src/vite/features.ts
+26
-36
packages/uni-cli-shared/src/vite/plugins/copy.ts
packages/uni-cli-shared/src/vite/plugins/copy.ts
+2
-5
packages/uni-cli-shared/src/watcher.ts
packages/uni-cli-shared/src/watcher.ts
+19
-3
packages/uni-h5-vite/src/plugins/pagesJson.ts
packages/uni-h5-vite/src/plugins/pagesJson.ts
+3
-1
packages/uni-h5/src/framework/components/page/pageHead.tsx
packages/uni-h5/src/framework/components/page/pageHead.tsx
+6
-6
packages/uni-i18n/__tests__/__snapshots__/json.spec.ts.snap
packages/uni-i18n/__tests__/__snapshots__/json.spec.ts.snap
+90
-0
packages/uni-i18n/__tests__/json.spec.ts
packages/uni-i18n/__tests__/json.spec.ts
+142
-0
packages/uni-i18n/dist/uni-i18n.cjs.js
packages/uni-i18n/dist/uni-i18n.cjs.js
+133
-16
packages/uni-i18n/dist/uni-i18n.d.ts
packages/uni-i18n/dist/uni-i18n.d.ts
+15
-2
packages/uni-i18n/dist/uni-i18n.es.js
packages/uni-i18n/dist/uni-i18n.es.js
+130
-17
packages/uni-i18n/src/I18n.ts
packages/uni-i18n/src/I18n.ts
+8
-4
packages/uni-i18n/src/format.ts
packages/uni-i18n/src/format.ts
+22
-14
packages/uni-i18n/src/index.ts
packages/uni-i18n/src/index.ts
+1
-0
packages/uni-i18n/src/json.ts
packages/uni-i18n/src/json.ts
+172
-0
packages/uni-i18n/src/vue-i18n.ts
packages/uni-i18n/src/vue-i18n.ts
+10
-1
packages/uni-shared/dist/uni-shared.cjs.js
packages/uni-shared/dist/uni-shared.cjs.js
+2
-0
packages/uni-shared/dist/uni-shared.d.ts
packages/uni-shared/dist/uni-shared.d.ts
+2
-0
packages/uni-shared/dist/uni-shared.es.js
packages/uni-shared/dist/uni-shared.es.js
+2
-1
packages/uni-shared/src/constants.ts
packages/uni-shared/src/constants.ts
+2
-0
packages/uni-stat/dist/uni-stat.cjs.js
packages/uni-stat/dist/uni-stat.cjs.js
+1
-1
packages/uni-stat/dist/uni-stat.es.js
packages/uni-stat/dist/uni-stat.es.js
+1
-1
未找到文件。
packages/shims-uni-app.d.ts
浏览文件 @
9dc717e3
...
...
@@ -188,6 +188,7 @@ declare namespace UniApp {
interface
PageRouteMeta
extends
PagesJsonPageStyle
{
id
?:
number
route
:
string
i18n
?:
boolean
isQuit
?:
boolean
isEntry
?:
boolean
isTabBar
?:
boolean
...
...
packages/uni-app-plus/dist/uni-app-service.es.js
浏览文件 @
9dc717e3
...
...
@@ -107,7 +107,7 @@ var serviceContext = (function (vue) {
const extend = Object.assign;
const hasOwnProperty$1 = Object.prototype.hasOwnProperty;
const hasOwn$1 = (val, key) => hasOwnProperty$1.call(val, key);
const isArray = Array.isArray;
const isArray
$1
= Array.isArray;
const isFunction = (val) => typeof val === 'function';
const isString = (val) => typeof val === 'string';
const isObject$1 = (val) => val !== null && typeof val === 'object';
...
...
@@ -164,7 +164,7 @@ var serviceContext = (function (vue) {
return str;
}
function elemsInArray(strArr, optionalVal) {
if (!isArray(strArr) ||
if (!isArray
$1
(strArr) ||
strArr.length === 0 ||
strArr.find((val) => optionalVal.indexOf(val) === -1)) {
return optionalVal;
...
...
@@ -189,7 +189,7 @@ var serviceContext = (function (vue) {
if (!protocol) {
return;
}
if (!isArray(protocol)) {
if (!isArray
$1
(protocol)) {
return validateProtocol(name, args[0] || Object.create(null), protocol, onFail);
}
const len = protocol.length;
...
...
@@ -219,7 +219,7 @@ var serviceContext = (function (vue) {
// type check
if (type != null) {
let isValid = false;
const types = isArray(type) ? type : [type];
const types = isArray
$1
(type) ? type : [type];
const expectedTypes = [];
// value is valid as long as one of the specified types match
for (let i = 0; i < types.length && !isValid; i++) {
...
...
@@ -252,7 +252,7 @@ var serviceContext = (function (vue) {
valid = isObject$1(value);
}
else if (expectedType === 'Array') {
valid = isArray(value);
valid = isArray
$1
(value);
}
else {
{
...
...
@@ -460,7 +460,7 @@ var serviceContext = (function (vue) {
function wrapperOptions(interceptors, options = {}) {
[HOOK_SUCCESS, HOOK_FAIL, HOOK_COMPLETE].forEach((name) => {
const hooks = interceptors[name];
if (!isArray(hooks)) {
if (!isArray
$1
(hooks)) {
return;
}
const oldCallback = options[name];
...
...
@@ -474,11 +474,11 @@ var serviceContext = (function (vue) {
}
function wrapperReturnValue(method, returnValue) {
const returnValueHooks = [];
if (isArray(globalInterceptors.returnValue)) {
if (isArray
$1
(globalInterceptors.returnValue)) {
returnValueHooks.push(...globalInterceptors.returnValue);
}
const interceptor = scopedInterceptors[method];
if (interceptor && isArray(interceptor.returnValue)) {
if (interceptor && isArray
$1
(interceptor.returnValue)) {
returnValueHooks.push(...interceptor.returnValue);
}
returnValueHooks.forEach((hook) => {
...
...
@@ -506,7 +506,7 @@ var serviceContext = (function (vue) {
function invokeApi(method, api, options, ...params) {
const interceptor = getApiInterceptorHooks(method);
if (interceptor && Object.keys(interceptor).length) {
if (isArray(interceptor.invoke)) {
if (isArray
$1
(interceptor.invoke)) {
const res = queue(interceptor.invoke, options);
return res.then((options) => {
return api(wrapperOptions(interceptor, options), ...params);
...
...
@@ -797,7 +797,7 @@ var serviceContext = (function (vue) {
if (key in query) {
// an extra variable for ts types
let currentValue = query[key];
if (!isArray(currentValue)) {
if (!isArray
$1
(currentValue)) {
currentValue = query[key] = [currentValue];
}
currentValue.push(value);
...
...
@@ -1262,18 +1262,20 @@ var serviceContext = (function (vue) {
ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED,
];
const isArray = Array.isArray;
const isObject = (val) => val !== null && typeof val === 'object';
const defaultDelimiters = ['{', '}'];
class BaseFormatter {
constructor() {
this._caches = Object.create(null);
}
interpolate(message, values) {
interpolate(message, values
, delimiters = defaultDelimiters
) {
if (!values) {
return [message];
}
let tokens = this._caches[message];
if (!tokens) {
tokens = parse(message);
tokens = parse(message
, delimiters
);
this._caches[message] = tokens;
}
return compile(tokens, values);
...
...
@@ -1281,24 +1283,24 @@ var serviceContext = (function (vue) {
}
const RE_TOKEN_LIST_VALUE = /^(?:\d)+/;
const RE_TOKEN_NAMED_VALUE = /^(?:\w)+/;
function parse(format) {
function parse(format
, [startDelimiter, endDelimiter]
) {
const tokens = [];
let position = 0;
let text = '';
while (position < format.length) {
let char = format[position++];
if (char ===
'{'
) {
if (char ===
startDelimiter
) {
if (text) {
tokens.push({ type: 'text', value: text });
}
text = '';
let sub = '';
char = format[position++];
while (char !== undefined && char !==
'}'
) {
while (char !== undefined && char !==
endDelimiter
) {
sub += char;
char = format[position++];
}
const isClosed = char ===
'}'
;
const isClosed = char ===
endDelimiter
;
const type = RE_TOKEN_LIST_VALUE.test(sub)
? 'list'
: isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
...
...
@@ -1306,12 +1308,12 @@ var serviceContext = (function (vue) {
: 'unknown';
tokens.push({ value: sub, type });
}
else if (char === '%') {
// when found rails i18n syntax, skip text capture
if (format[position] !== '{') {
text += char;
}
}
//
else if (char === '%') {
//
// when found rails i18n syntax, skip text capture
//
if (format[position] !== '{') {
// text += char
//
}
//
}
else {
text += char;
}
...
...
@@ -1322,7 +1324,7 @@ var serviceContext = (function (vue) {
function compile(tokens, values) {
const compiled = [];
let index = 0;
const mode =
Array.
isArray(values)
const mode = isArray(values)
? 'list'
: isObject(values)
? 'named'
...
...
@@ -1425,9 +1427,12 @@ var serviceContext = (function (vue) {
this.messages[this.locale] = {};
}
this.message = this.messages[this.locale];
this.watchers.forEach((watcher) => {
watcher(this.locale, oldLocale);
});
// 仅发生变化时,通知
if (oldLocale !== this.locale) {
this.watchers.forEach((watcher) => {
watcher(this.locale, oldLocale);
});
}
}
getLocale() {
return this.locale;
...
...
@@ -1543,6 +1548,9 @@ var serviceContext = (function (vue) {
add(locale, message) {
return i18n.add(locale, message);
},
watch(fn) {
return i18n.watchLocale(fn);
},
getLocale() {
return i18n.getLocale();
},
...
...
@@ -2611,7 +2619,7 @@ var serviceContext = (function (vue) {
const res = childVal
? parentVal
? parentVal.concat(childVal)
: isArray(childVal)
: isArray
$1
(childVal)
? childVal
: [childVal]
: parentVal;
...
...
@@ -7350,7 +7358,7 @@ var serviceContext = (function (vue) {
plus.gallery.save(options.filePath, warpPlusSuccessCallback(resolve), warpPlusErrorCallback(reject));
}, SaveImageToPhotosAlbumProtocol, SaveImageToPhotosAlbumOptions);
const compressImage = defineAsyncApi(API_COMPRESS_IMAGE, (options, { resolve, reject }) => {
const compressImage
$1
= defineAsyncApi(API_COMPRESS_IMAGE, (options, { resolve, reject }) => {
const dst = `${TEMP_PATH}/compressed/${Date.now()}_${getFileName(options.src)}`;
plus.zip.compressImage(extend({}, options, {
dst,
...
...
@@ -7384,6 +7392,23 @@ var serviceContext = (function (vue) {
}, reject);
});
}
function compressImage(tempFilePath) {
const dst = `${TEMP_PATH}/compressed/${Date.now()}_${getFileName(tempFilePath)}`;
return new Promise((resolve) => {
plus.nativeUI.showWaiting();
plus.zip.compressImage({
src: tempFilePath,
dst,
overwrite: true,
}, () => {
plus.nativeUI.closeWaiting();
resolve(dst);
}, () => {
plus.nativeUI.closeWaiting();
resolve(tempFilePath);
});
});
}
const chooseImage = defineAsyncApi(API_CHOOSE_IMAGE,
// @ts-ignore crop 属性App特有
({ count, sizeType, sourceType, crop } = {}, { resolve, reject }) => {
...
...
@@ -7409,7 +7434,22 @@ var serviceContext = (function (vue) {
}
function openCamera() {
const camera = plus.camera.getCamera();
camera.captureImage((path) => successCallback([path]), errorCallback, {
camera.captureImage((path) => {
// fix By Lxh 暂时添加拍照压缩逻辑,等客户端增加逻辑后修改
// 判断是否需要压缩
if (sizeType && sizeType.includes('compressed')) {
return getFileInfo(path)
.then(({ size }) => {
// 压缩阈值 0.5 兆
const THRESHOLD = 1024 * 1024 * 0.5;
return size && size > THRESHOLD
? compressImage(path).then((dstPath) => successCallback([dstPath]))
: successCallback([path]);
})
.catch(errorCallback);
}
return successCallback([path]);
}, errorCallback, {
filename: TEMP_PATH + '/camera/',
resolution: 'high',
crop,
...
...
@@ -9717,7 +9757,7 @@ var serviceContext = (function (vue) {
Object.keys(options).forEach((name) => {
if (name.indexOf('on') === 0) {
const hooks = options[name];
if (isArray(hooks)) {
if (isArray
$1
(hooks)) {
hooks.forEach((hook) => injectLifecycleHook(name, hook, publicThis, instance));
}
else {
...
...
@@ -9740,7 +9780,7 @@ var serviceContext = (function (vue) {
initModules(instance, options.$renderjs, options['$' + RENDERJS_MODULES]);
}
function initModules(instance, modules, moduleIds = {}) {
if (!isArray(modules)) {
if (!isArray
$1
(modules)) {
return;
}
const ownerId = instance.uid;
...
...
@@ -10309,7 +10349,7 @@ var serviceContext = (function (vue) {
else if (name === 'titleImage' && value) {
titleNView.tags = createTitleImageTags(value);
}
else if (name === 'buttons' && isArray(value)) {
else if (name === 'buttons' && isArray
$1
(value)) {
titleNView.buttons = value.map((button, index) => {
button.onclick = createTitleNViewBtnClick(index);
return button;
...
...
@@ -12468,7 +12508,7 @@ var serviceContext = (function (vue) {
getRecorderManager: getRecorderManager,
saveVideoToPhotosAlbum: saveVideoToPhotosAlbum,
saveImageToPhotosAlbum: saveImageToPhotosAlbum,
compressImage: compressImage,
compressImage: compressImage
$1
,
compressVideo: compressVideo,
chooseImage: chooseImage,
chooseVideo: chooseVideo,
...
...
@@ -12548,7 +12588,7 @@ var serviceContext = (function (vue) {
if ((process.env.NODE_ENV !== 'production')) {
console.log(formatLog('publishHandler', event, args, pageIds));
}
if (!isArray(pageIds)) {
if (!isArray
$1
(pageIds)) {
pageIds = [pageIds];
}
const evalJSCode = `typeof UniViewJSBridge !== 'undefined' && UniViewJSBridge.subscribeHandler("${event}",${args},__PAGE_ID__)`;
...
...
packages/uni-app-plus/dist/uni-app-view.umd.js
浏览文件 @
9dc717e3
因为 它太大了无法显示 source diff 。你可以改为
查看blob
。
packages/uni-app-plus/src/service/framework/amd/index.ts
浏览文件 @
9dc717e3
...
...
@@ -24,11 +24,15 @@ export type Define = typeof def
export
type
Require
=
typeof
req
export
type
Exports
=
Record
<
string
,
any
>
export
function
def
(
name
:
string
,
deps
:
string
[],
definition
:
Function
)
{
req
(
deps
,
()
=>
resolve
(
name
,
definition
()))
export
function
def
(
name
:
string
,
deps
:
string
[],
definition
:
(...
args
:
any
[])
=>
void
)
{
req
(
deps
,
()
=>
resolve
(
name
))
}
export
function
req
(
modules
:
string
[],
definition
:
Function
)
{
export
function
req
(
modules
:
string
[],
definition
:
(...
args
:
any
[])
=>
void
)
{
Promise
.
all
(
modules
.
map
(
deps
)).
then
((
result
)
=>
definition
.
apply
(
null
,
result
)
)
...
...
packages/uni-app-vite/src/plugin/uni/index.ts
浏览文件 @
9dc717e3
...
...
@@ -2,16 +2,35 @@ import {
isServiceNativeTag
,
isServiceCustomElement
,
}
from
'
@dcloudio/uni-shared
'
import
{
UniVitePlugin
}
from
'
@dcloudio/uni-cli-shared
'
import
{
compileI18nJsonStr
}
from
'
@dcloudio/uni-i18n
'
import
{
UniVitePlugin
,
initI18nOptions
,
getFallbackLocale
,
}
from
'
@dcloudio/uni-cli-shared
'
export
function
uniOptions
():
UniVitePlugin
[
'
uni
'
]
{
return
{
copyOptions
()
{
const
inputDir
=
process
.
env
.
UNI_INPUT_DIR
const
outputDir
=
process
.
env
.
UNI_OUTPUT_DIR
return
{
assets
:
[
'
androidPrivacy.json
'
,
'
hybrid/html/**/*
'
,
'
uni_modules/*/hybrid/html/**/*
'
,
assets
:
[
'
hybrid/html/**/*
'
,
'
uni_modules/*/hybrid/html/**/*
'
],
targets
:
[
{
src
:
'
androidPrivacy.json
'
,
dest
:
outputDir
,
transform
(
source
)
{
const
options
=
initI18nOptions
(
inputDir
,
getFallbackLocale
(
inputDir
)
)
if
(
!
options
)
{
return
}
return
compileI18nJsonStr
(
source
.
toString
(),
options
)
},
},
],
}
},
...
...
packages/uni-cli-shared/__tests__/i18n.spec.ts
0 → 100644
浏览文件 @
9dc717e3
import
{
normalizeI18nLocale
}
from
'
../src/i18n
'
describe
(
'
normalizeI18nLocale
'
,
()
=>
{
test
(
'
specifying locale
'
,
()
=>
{
expect
(
normalizeI18nLocale
({
'
zh-Hans
'
:
{},
fr
:
{}
},
'
fr
'
)).
toBe
(
'
fr
'
)
})
test
(
'
fallback en
'
,
()
=>
{
expect
(
normalizeI18nLocale
({
'
zh-Hans
'
:
{},
en
:
{}
},
'
fr
'
)).
toBe
(
'
en
'
)
})
test
(
'
fallback zh-Hans
'
,
()
=>
{
expect
(
normalizeI18nLocale
({
'
zh-Hans
'
:
{},
es
:
{}
})).
toBe
(
'
zh-Hans
'
)
})
test
(
'
fallback zh-Hant
'
,
()
=>
{
expect
(
normalizeI18nLocale
({
'
zh-Hant
'
:
{},
es
:
{}
})).
toBe
(
'
zh-Hant
'
)
})
test
(
'
fallback first locale
'
,
()
=>
{
expect
(
normalizeI18nLocale
({
fr
:
{},
es
:
{}
})).
toBe
(
'
fr
'
)
})
})
packages/uni-cli-shared/src/i18n.ts
0 → 100644
浏览文件 @
9dc717e3
import
fs
from
'
fs
'
import
path
from
'
path
'
import
{
I18N_JSON_DELIMITERS
}
from
'
@dcloudio/uni-shared
'
export
function
initI18nOptions
(
inputDir
:
string
,
fallbackLocale
?:
string
)
{
const
locales
=
initLocales
(
path
.
resolve
(
inputDir
,
'
locale
'
))
if
(
!
Object
.
keys
(
locales
).
length
)
{
return
}
const
locale
=
normalizeI18nLocale
(
locales
,
fallbackLocale
)
return
{
locale
,
locales
,
delimiters
:
I18N_JSON_DELIMITERS
,
}
}
function
initLocales
(
dir
:
string
)
{
if
(
!
fs
.
existsSync
(
dir
))
{
return
{}
}
return
fs
.
readdirSync
(
dir
).
reduce
((
res
,
filename
)
=>
{
if
(
path
.
extname
(
filename
)
===
'
.json
'
)
{
try
{
res
[
path
.
basename
(
filename
).
replace
(
'
.json
'
,
''
)]
=
JSON
.
parse
(
fs
.
readFileSync
(
path
.
join
(
dir
,
filename
),
'
utf8
'
)
)
}
catch
(
e
)
{}
}
return
res
},
{}
as
Record
<
string
,
Record
<
string
,
string
>>
)
}
const
defaultFallbackLocale
=
'
en
'
// specifying locale > en > zh-Hans > zh-Hant > first locale
export
function
normalizeI18nLocale
(
locales
:
Record
<
string
,
Record
<
string
,
string
>>
,
locale
:
string
=
defaultFallbackLocale
)
{
if
(
locales
[
locale
])
{
return
locale
}
return
(
[
'
en
'
,
'
zh-Hans
'
,
'
zh-Hant
'
].
find
((
n
)
=>
locales
[
n
])
||
Object
.
keys
(
locales
)[
0
]
||
defaultFallbackLocale
)
}
packages/uni-cli-shared/src/index.ts
浏览文件 @
9dc717e3
...
...
@@ -3,6 +3,7 @@ export * from './env'
export
*
from
'
./hbx
'
export
*
from
'
./logs
'
export
*
from
'
./ssr
'
export
*
from
'
./i18n
'
export
*
from
'
./deps
'
export
*
from
'
./json
'
export
*
from
'
./vite
'
...
...
packages/uni-cli-shared/src/json/app/manifest/merge.ts
浏览文件 @
9dc717e3
import
{
recursive
}
from
'
merge
'
import
{
M
}
from
'
../../../messages
'
import
{
initI18nOptions
}
from
'
../../../i18n
'
export
function
initRecursiveMerge
(
manifestJson
:
Record
<
string
,
any
>
,
userManifestJson
:
Record
<
string
,
any
>
):
Record
<
string
,
any
>
{
const
i18nOptions
=
initI18nOptions
(
process
.
env
.
UNI_INPUT_DIR
,
userManifestJson
.
fallbackLocale
)
let
fallbackLocale
:
string
|
undefined
=
undefined
if
(
i18nOptions
)
{
fallbackLocale
=
i18nOptions
.
locale
if
(
!
userManifestJson
.
fallbackLocale
)
{
console
.
warn
(
M
[
'
i18n.fallbackLocale.missing
'
].
replace
(
'
{locale}
'
,
fallbackLocale
)
)
}
else
if
(
userManifestJson
.
fallbackLocale
!==
fallbackLocale
)
{
console
.
warn
(
M
[
'
i18n.fallbackLocale.unmatch
'
].
replace
(
'
{locale}
'
,
userManifestJson
.
fallbackLocale
)
)
}
}
return
recursive
(
true
,
manifestJson
,
...
...
@@ -15,7 +37,8 @@ export function initRecursiveMerge(
name
:
userManifestJson
.
versionName
,
code
:
userManifestJson
.
versionCode
,
},
language
:
userManifestJson
.
locale
,
locale
:
userManifestJson
.
locale
,
fallbackLocale
,
},
{
plus
:
userManifestJson
[
'
app-plus
'
]
}
)
...
...
packages/uni-cli-shared/src/json/manifest.ts
浏览文件 @
9dc717e3
...
...
@@ -52,3 +52,8 @@ export function getUniStatistics(inputDir: string, platform: UniApp.PLATFORM) {
manifest
[
platform
]
&&
manifest
[
platform
].
uniStatistics
)
}
export
function
getFallbackLocale
(
inputDir
:
string
)
{
const
manifest
=
parseManifestJsonOnce
(
inputDir
)
return
manifest
.
fallbackLocale
}
packages/uni-cli-shared/src/messages/index.ts
浏览文件 @
9dc717e3
...
...
@@ -12,4 +12,8 @@ export const M = {
'
dev.watching.end.files
'
:
'
DONE Build complete. FILES:{files}
'
,
'
stat.warn.appid
'
:
'
当前应用未配置Appid,无法使用uni统计,详情参考:https://ask.dcloud.net.cn/article/36303
'
,
'
i18n.fallbackLocale.missing
'
:
'
当前应用未在manifest.json配置fallbackLocale,默认使用:{locale}
'
,
'
i18n.fallbackLocale.unmatch
'
:
'
当前应用配置的fallbackLocale为:${locale},但locale目录缺少该语言文件
'
,
}
packages/uni-cli-shared/src/vite/features.ts
浏览文件 @
9dc717e3
...
...
@@ -3,7 +3,14 @@ import path from 'path'
import
{
ConfigEnv
}
from
'
vite
'
import
{
extend
,
isArray
,
isString
}
from
'
@vue/shared
'
interface
ProjectFeatures
{}
interface
ProjectFeatures
{
i18nLocales
:
boolean
i18nEn
:
boolean
i18nEs
:
boolean
i18nFr
:
boolean
i18nZhHans
:
boolean
i18nZhHant
:
boolean
}
interface
PagesFeatures
{
nvue
:
boolean
pages
:
boolean
...
...
@@ -25,18 +32,26 @@ interface ManifestFeatures {
promise
:
boolean
longpress
:
boolean
routerMode
:
'
"hash"
'
|
'
"history"
'
i18nEn
:
boolean
i18nEs
:
boolean
i18nFr
:
boolean
i18nZhHans
:
boolean
i18nZhHant
:
boolean
vueOptionsApi
:
boolean
vueProdDevTools
:
boolean
}
function
initProjectFeature
({
command
}:
InitFeaturesOptions
)
{
const
features
:
ProjectFeatures
=
{}
if
(
command
===
'
build
'
)
{
function
initProjectFeature
({
inputDir
}:
InitFeaturesOptions
)
{
const
features
:
ProjectFeatures
=
{
i18nLocales
:
false
,
i18nEn
:
true
,
i18nEs
:
true
,
i18nFr
:
true
,
i18nZhHans
:
true
,
i18nZhHant
:
true
,
}
const
localesDir
=
path
.
resolve
(
inputDir
,
'
locales
'
)
if
(
fs
.
existsSync
(
localesDir
))
{
if
(
fs
.
readdirSync
(
localesDir
).
find
((
file
)
=>
path
.
extname
(
file
)
===
'
.json
'
)
)
{
features
.
i18nLocales
=
true
}
}
return
features
}
...
...
@@ -155,11 +170,6 @@ function initManifestFeature({
promise
:
false
,
longpress
:
true
,
routerMode
:
'
"hash"
'
,
i18nEn
:
true
,
i18nEs
:
true
,
i18nFr
:
true
,
i18nZhHans
:
true
,
i18nZhHant
:
true
,
vueOptionsApi
:
true
,
vueProdDevTools
:
false
,
}
...
...
@@ -176,28 +186,6 @@ function initManifestFeature({
)
{
features
.
routerMode
=
'
"history"
'
}
const
platformJson
=
manifestJson
[
platform
]
||
{}
const
manifestFeatures
=
platformJson
.
features
if
(
manifestFeatures
)
{
const
{
i18n
}
=
manifestFeatures
if
(
isArray
(
i18n
))
{
if
(
!
i18n
.
includes
(
'
en
'
))
{
features
.
i18nEn
=
false
}
if
(
!
i18n
.
includes
(
'
es
'
))
{
features
.
i18nEs
=
false
}
if
(
!
i18n
.
includes
(
'
fr
'
))
{
features
.
i18nFr
=
false
}
if
(
!
i18n
.
includes
(
'
zh-Hans
'
))
{
features
.
i18nZhHans
=
false
}
if
(
!
i18n
.
includes
(
'
zh-Hant
'
))
{
features
.
i18nZhHant
=
false
}
}
}
// TODO other features
return
features
}
...
...
@@ -224,6 +212,7 @@ export function initFeatures(options: InitFeaturesOptions) {
i18nFr
,
i18nZhHans
,
i18nZhHant
,
i18nLocales
,
vueOptionsApi
,
vueProdDevTools
,
pages
,
...
...
@@ -261,6 +250,7 @@ export function initFeatures(options: InitFeaturesOptions) {
__UNI_FEATURE_I18N_ZH_HANS__
:
i18nZhHans
,
// 是否启用zh_Hans
__UNI_FEATURE_I18N_ZH_HANT__
:
i18nZhHant
,
// 是否启用zh_Hant
// 以下特性,编译器已自动识别是否需要启用
__UNI_FEATURE_I18N_LOCALES__
:
i18nLocales
,
// 是否启用i18n
__UNI_FEATURE_NVUE__
:
nvue
,
// 是否启用nvue
__UNI_FEATURE_ROUTER_MODE__
:
routerMode
,
// 路由模式
__UNI_FEATURE_PAGES__
:
pages
,
// 是否多页面
...
...
packages/uni-cli-shared/src/vite/plugins/copy.ts
浏览文件 @
9dc717e3
import
{
Plugin
,
ResolvedConfig
}
from
'
vite
'
import
{
FileWatcher
}
from
'
../../watcher
'
import
{
FileWatcher
,
FileWatcherOptions
}
from
'
../../watcher
'
import
{
M
}
from
'
../../messages
'
export
interface
UniViteCopyPluginTarget
{
src
:
string
|
string
[]
dest
:
string
}
export
type
UniViteCopyPluginTarget
=
Omit
<
FileWatcherOptions
,
'
verbose
'
>
export
interface
UniViteCopyPluginOptions
{
targets
:
UniViteCopyPluginTarget
[]
verbose
:
boolean
...
...
packages/uni-cli-shared/src/watcher.ts
浏览文件 @
9dc717e3
import
fs
from
'
fs-extra
'
import
path
from
'
path
'
import
{
FSWatcher
,
watch
,
WatchOptions
}
from
'
chokidar
'
interface
FileWatcherOptions
{
type
FileTransform
=
(
source
:
Buffer
,
filename
:
string
)
=>
void
|
string
export
interface
FileWatcherOptions
{
src
:
string
|
string
[]
dest
:
string
transform
?:
FileTransform
verbose
?:
boolean
}
export
class
FileWatcher
{
private
src
:
string
[]
private
dest
:
string
private
transform
?:
FileTransform
private
verbose
?:
boolean
private
watcher
!
:
FSWatcher
private
onChange
?:
()
=>
void
constructor
({
src
,
dest
,
verbose
}:
FileWatcherOptions
)
{
constructor
({
src
,
dest
,
transform
,
verbose
}:
FileWatcherOptions
)
{
this
.
src
=
!
Array
.
isArray
(
src
)
?
[
src
]
:
src
this
.
dest
=
dest
this
.
transform
=
transform
this
.
verbose
=
verbose
}
watch
(
...
...
@@ -57,6 +60,19 @@ export class FileWatcher {
copy
(
from
:
string
)
{
const
to
=
this
.
to
(
from
)
this
.
info
(
'
copy
'
,
from
+
'
=>
'
+
to
)
let
content
:
string
|
void
if
(
this
.
transform
)
{
const
filename
=
this
.
from
(
from
)
content
=
this
.
transform
(
fs
.
readFileSync
(
filename
),
filename
)
}
if
(
content
)
{
return
fs
.
outputFile
(
to
,
content
)
.
catch
((
e
)
=>
{
// this.info('copy', e)
})
.
then
(()
=>
this
.
onChange
&&
this
.
onChange
())
}
return
fs
.
copy
(
this
.
from
(
from
),
to
,
{
overwrite
:
true
})
.
catch
((
e
)
=>
{
...
...
packages/uni-h5-vite/src/plugins/pagesJson.ts
浏览文件 @
9dc717e3
...
...
@@ -56,6 +56,7 @@ function generatePagesJsonCode(
import { defineAsyncComponent, resolveComponent, createVNode, withCtx, openBlock, createBlock } from 'vue'
import { PageComponent, AsyncLoadingComponent, AsyncErrorComponent, setupWindow } from '@dcloudio/uni-h5'
import { appid, debug, networkTimeout, router, async, sdkConfigs, qqMapKey, nvue, locale } from '
${
manifestJsonPath
}
'
const locales = import.meta.globEager('./locale/*.json')
${
importLayoutComponentsCode
}
const extend = Object.assign
${
cssCode
}
...
...
@@ -260,7 +261,8 @@ delete ${globalName}['____'+appid+'____']
qqMapKey,
nvue,
locale,
router
locales:Object.keys(locales).reduce((res,name)=>{res[name.replace(/\\.\\/locale\\/(.*).json/,'$1')]=locales[name].default;return res},{}),
router,
})
`
)
...
...
packages/uni-h5/src/framework/components/page/pageHead.tsx
浏览文件 @
9dc717e3
...
...
@@ -315,7 +315,7 @@ function usePageHeadButtons({ id, navigationBar }: UniApp.PageRouteMeta) {
}
btn
.
fontFamily
=
fontFamily
}
const
pageHeadBtn
=
usePageHeadButton
(
id
,
index
,
btn
,
isTransparent
)
const
pageHeadBtn
=
usePageHeadButton
(
id
!
,
index
,
btn
,
isTransparent
)
if
(
btn
.
float
===
'
left
'
)
{
left
.
push
(
pageHeadBtn
)
}
else
{
...
...
@@ -374,7 +374,7 @@ function usePageHeadSearchInput({
const
{
disabled
}
=
searchInput
!
if
(
disabled
)
{
const
onClick
=
()
=>
{
invokeHook
(
id
,
'
onNavigationBarSearchInputClicked
'
)
invokeHook
(
id
!
,
'
onNavigationBarSearchInputClicked
'
)
}
return
{
focus
,
...
...
@@ -385,19 +385,19 @@ function usePageHeadSearchInput({
}
const
onFocus
=
()
=>
{
focus
.
value
=
true
invokeHook
(
id
,
'
onNavigationBarSearchInputFocusChanged
'
,
{
focus
:
true
})
invokeHook
(
id
!
,
'
onNavigationBarSearchInputFocusChanged
'
,
{
focus
:
true
})
}
const
onBlur
=
()
=>
{
focus
.
value
=
false
invokeHook
(
id
,
'
onNavigationBarSearchInputFocusChanged
'
,
{
focus
:
false
})
invokeHook
(
id
!
,
'
onNavigationBarSearchInputFocusChanged
'
,
{
focus
:
false
})
}
const
onInput
=
(
evt
:
{
detail
:
{
value
:
string
}
})
=>
{
text
.
value
=
evt
.
detail
.
value
invokeHook
(
id
,
'
onNavigationBarSearchInputChanged
'
,
{
text
:
text
.
value
})
invokeHook
(
id
!
,
'
onNavigationBarSearchInputChanged
'
,
{
text
:
text
.
value
})
}
const
onKeyup
=
(
evt
:
KeyboardEvent
)
=>
{
if
(
evt
.
key
===
'
Enter
'
||
evt
.
keyCode
===
13
)
{
invokeHook
(
id
,
'
onNavigationBarSearchInputConfirmed
'
,
{
invokeHook
(
id
!
,
'
onNavigationBarSearchInputConfirmed
'
,
{
text
:
text
.
value
,
})
}
...
...
packages/uni-i18n/__tests__/__snapshots__/json.spec.ts.snap
0 → 100644
浏览文件 @
9dc717e3
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`compileI18nJsonStr androidPrivacy.json 1`] = `
"{
\\"version\\": \\"1\\",
\\"prompt\\": \\"template\\",
\\"title\\": \\"服务协议和隐私政策\\",
\\"message\\": \\" 请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/> 你可阅读<a href=\\\\\\"\\\\\\">《服务协议》</a>和<a href=\\\\\\"\\\\\\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。\\",
\\"buttonAccept\\": \\"同意并接受\\",
\\"buttonRefuse\\": \\"暂不同意\\",
\\"second\\": {
\\"title\\": \\"确认提示\\",
\\"message\\": \\" 进入应用前,你需先同意<a href=\\\\\\"\\\\\\">《服务协议》</a>和<a href=\\\\\\"\\\\\\">《隐私政策》</a>,否则将退出应用。\\",
\\"buttonAccept\\": \\"同意并继续\\",
\\"buttonRefuse\\": \\"退出应用\\",
\\"titleLocales\\": {
\\"zh-Hans\\": \\"确认提示\\",
\\"en\\": \\"confirm\\"
}
},
\\"styles\\": {
\\"backgroundColor\\": \\"#00FF00\\",
\\"borderRadius\\": \\"5px\\",
\\"title\\": {
\\"color\\": \\"#ff00ff\\",
\\"colorLocales\\": {
\\"zh-Hans\\": \\"#ff00ff\\",
\\"en\\": \\"#ff00ff\\"
}
},
\\"buttonAccept\\": {
\\"color\\": \\"#ffff00\\"
},
\\"buttonRefuse\\": {
\\"color\\": \\"#00ffff\\"
}
},
\\"titleLocales\\": {
\\"zh-Hans\\": \\"服务协议和隐私政策\\",
\\"en\\": \\"Privacy\\"
},
\\"messageLocales\\": {
\\"zh-Hans\\": \\" 请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/> 你可阅读<a href=\\\\\\"\\\\\\">《服务协议》</a>和<a href=\\\\\\"\\\\\\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。\\",
\\"en\\": \\" privacy\\"
},
\\"buttonAcceptLocales\\": {
\\"zh-Hans\\": \\"同意并接受\\",
\\"en\\": \\"accept\\"
},
\\"buttonRefuseLocales\\": {
\\"zh-Hans\\": \\"暂不同意\\",
\\"en\\": \\"refuse\\"
}
}"
`;
exports[`compileI18nJsonStr pages.json->tabBar 1`] = `
"{
\\"color\\": \\"#7A7E83\\",
\\"selectedColor\\": \\"#007AFF\\",
\\"borderStyle\\": \\"black\\",
\\"backgroundColor\\": \\"#f8f8f8\\",
\\"list\\": [
{
\\"pagePath\\": \\"pages/tabBar/component/component\\",
\\"iconPath\\": \\"static/component.png\\",
\\"selectedIconPath\\": \\"static/componentHL.png\\",
\\"text\\": \\"组件\\",
\\"textLocales\\": {
\\"zh-Hans\\": \\"组件\\",
\\"en\\": \\"Component\\"
}
},
{
\\"pagePath\\": \\"pages/tabBar/API/API\\",
\\"iconPath\\": \\"static/api.png\\",
\\"selectedIconPath\\": \\"static/apiHL.png\\",
\\"text\\": \\"接口\\",
\\"textLocales\\": {
\\"zh-Hans\\": \\"接口\\",
\\"en\\": \\"API\\"
}
}
],
\\"backgroundColorLocales\\": {
\\"zh-Hans\\": \\"#f8f8f8\\",
\\"en\\": \\"#f6f6f6\\"
}
}"
`;
packages/uni-i18n/__tests__/json.spec.ts
0 → 100644
浏览文件 @
9dc717e3
import
{
I18N_JSON_DELIMITERS
}
from
'
@dcloudio/uni-shared
'
import
{
parseI18nJson
,
compileI18nJsonStr
}
from
'
../src/json
'
const
delimiters
:
[
string
,
string
]
=
I18N_JSON_DELIMITERS
describe
(
'
parseI18nJson
'
,
()
=>
{
test
(
'
pages.json->style
'
,
()
=>
{
const
pageMeta
=
parseI18nJson
(
{
tabBarIndex
:
0
,
bounce
:
'
vertical
'
,
navigationBar
:
{
titleText
:
'
%component.title%组件
'
,
buttons
:
[
{
text
:
'
%component.btns.0.text%
'
,
fontSrc
:
'
/static/uni.ttf
'
,
fontSize
:
'
22px
'
,
color
:
'
#FFFFFF
'
,
},
],
},
route
:
'
pages/tabBar/component/component
'
,
},
{
'
component.title
'
:
'
内置
'
,
'
component.btns.0.text
'
:
'
\
ue534
'
,
},
delimiters
)
as
Record
<
string
,
any
>
expect
(
pageMeta
.
navigationBar
.
titleText
).
toBe
(
'
内置组件
'
)
expect
(
pageMeta
.
navigationBar
.
buttons
[
0
].
text
).
toBe
(
'
\
ue534
'
)
})
})
describe
(
'
compileI18nJsonStr
'
,
()
=>
{
test
(
'
empty
'
,
()
=>
{
expect
(
compileI18nJsonStr
(
JSON
.
stringify
({}),
{
locale
:
''
,
locales
:
{},
delimiters
,
})
).
toBe
(
'
{}
'
)
})
test
(
'
pages.json->tabBar
'
,
()
=>
{
expect
(
compileI18nJsonStr
(
JSON
.
stringify
({
color
:
'
#7A7E83
'
,
selectedColor
:
'
#007AFF
'
,
borderStyle
:
'
black
'
,
backgroundColor
:
'
#%tabBar.backgroundColor%
'
,
list
:
[
{
pagePath
:
'
pages/tabBar/component/component
'
,
iconPath
:
'
static/component.png
'
,
selectedIconPath
:
'
static/componentHL.png
'
,
text
:
'
%tabBar.0.title%
'
,
},
{
pagePath
:
'
pages/tabBar/API/API
'
,
iconPath
:
'
static/api.png
'
,
selectedIconPath
:
'
static/apiHL.png
'
,
text
:
'
%tabBar.1.title%
'
,
},
],
}),
{
locale
:
'
zh-Hans
'
,
locales
:
{
'
zh-Hans
'
:
{
'
tabBar.backgroundColor
'
:
'
f8f8f8
'
,
'
tabBar.0.title
'
:
'
组件
'
,
'
tabBar.1.title
'
:
'
接口
'
,
},
en
:
{
'
tabBar.backgroundColor
'
:
'
f6f6f6
'
,
'
tabBar.0.title
'
:
'
Component
'
,
'
tabBar.1.title
'
:
'
API
'
,
},
},
delimiters
,
}
)
).
toMatchSnapshot
()
})
test
(
'
androidPrivacy.json
'
,
()
=>
{
expect
(
compileI18nJsonStr
(
JSON
.
stringify
({
version
:
'
1
'
,
prompt
:
'
template
'
,
title
:
'
%p.title%
'
,
message
:
'
%p.message%
'
,
buttonAccept
:
'
%p.accept%
'
,
buttonRefuse
:
'
%p.refuse%
'
,
second
:
{
title
:
'
%p.second.title%
'
,
message
:
'
进入应用前,你需先同意<a href="">《服务协议》</a>和<a href="">《隐私政策》</a>,否则将退出应用。
'
,
buttonAccept
:
'
同意并继续
'
,
buttonRefuse
:
'
退出应用
'
,
},
styles
:
{
backgroundColor
:
'
#00FF00
'
,
borderRadius
:
'
5px
'
,
title
:
{
color
:
'
%p.title.color%
'
,
},
buttonAccept
:
{
color
:
'
#ffff00
'
,
},
buttonRefuse
:
{
color
:
'
#00ffff
'
,
},
},
}),
{
locale
:
'
zh-Hans
'
,
locales
:
{
'
zh-Hans
'
:
{
'
p.title
'
:
'
服务协议和隐私政策
'
,
'
p.message
'
:
'
请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/> 你可阅读<a href="">《服务协议》</a>和<a href="">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。
'
,
'
p.accept
'
:
'
同意并接受
'
,
'
p.refuse
'
:
'
暂不同意
'
,
'
p.second.title
'
:
'
确认提示
'
,
'
p.title.color
'
:
'
#ff00ff
'
,
},
en
:
{
'
p.title
'
:
'
Privacy
'
,
'
p.message
'
:
'
privacy
'
,
'
p.accept
'
:
'
accept
'
,
'
p.refuse
'
:
'
refuse
'
,
'
p.second.title
'
:
'
confirm
'
,
'
p.title.color
'
:
'
#ff00ff
'
,
},
},
delimiters
,
}
)
).
toMatchSnapshot
()
})
})
packages/uni-i18n/dist/uni-i18n.cjs.js
浏览文件 @
9dc717e3
...
...
@@ -2,18 +2,20 @@
Object
.
defineProperty
(
exports
,
'
__esModule
'
,
{
value
:
true
});
const
isArray
=
Array
.
isArray
;
const
isObject
=
(
val
)
=>
val
!==
null
&&
typeof
val
===
'
object
'
;
const
defaultDelimiters
=
[
'
{
'
,
'
}
'
];
class
BaseFormatter
{
constructor
()
{
this
.
_caches
=
Object
.
create
(
null
);
}
interpolate
(
message
,
values
)
{
interpolate
(
message
,
values
,
delimiters
=
defaultDelimiters
)
{
if
(
!
values
)
{
return
[
message
];
}
let
tokens
=
this
.
_caches
[
message
];
if
(
!
tokens
)
{
tokens
=
parse
(
message
);
tokens
=
parse
(
message
,
delimiters
);
this
.
_caches
[
message
]
=
tokens
;
}
return
compile
(
tokens
,
values
);
...
...
@@ -21,24 +23,24 @@ class BaseFormatter {
}
const
RE_TOKEN_LIST_VALUE
=
/^
(?:\d)
+/
;
const
RE_TOKEN_NAMED_VALUE
=
/^
(?:\w)
+/
;
function
parse
(
format
)
{
function
parse
(
format
,
[
startDelimiter
,
endDelimiter
]
)
{
const
tokens
=
[];
let
position
=
0
;
let
text
=
''
;
while
(
position
<
format
.
length
)
{
let
char
=
format
[
position
++
];
if
(
char
===
'
{
'
)
{
if
(
char
===
startDelimiter
)
{
if
(
text
)
{
tokens
.
push
({
type
:
'
text
'
,
value
:
text
});
}
text
=
''
;
let
sub
=
''
;
char
=
format
[
position
++
];
while
(
char
!==
undefined
&&
char
!==
'
}
'
)
{
while
(
char
!==
undefined
&&
char
!==
endDelimiter
)
{
sub
+=
char
;
char
=
format
[
position
++
];
}
const
isClosed
=
char
===
'
}
'
;
const
isClosed
=
char
===
endDelimiter
;
const
type
=
RE_TOKEN_LIST_VALUE
.
test
(
sub
)
?
'
list
'
:
isClosed
&&
RE_TOKEN_NAMED_VALUE
.
test
(
sub
)
...
...
@@ -46,12 +48,12 @@ function parse(format) {
:
'
unknown
'
;
tokens
.
push
({
value
:
sub
,
type
});
}
else
if
(
char
===
'
%
'
)
{
// when found rails i18n syntax, skip text capture
if
(
format
[
position
]
!==
'
{
'
)
{
text
+=
char
;
}
}
//
else if (char === '%') {
//
// when found rails i18n syntax, skip text capture
//
if (format[position] !== '{') {
// text += char
//
}
//
}
else
{
text
+=
char
;
}
...
...
@@ -62,7 +64,7 @@ function parse(format) {
function
compile
(
tokens
,
values
)
{
const
compiled
=
[];
let
index
=
0
;
const
mode
=
Array
.
isArray
(
values
)
const
mode
=
isArray
(
values
)
?
'
list
'
:
isObject
(
values
)
?
'
named
'
...
...
@@ -165,9 +167,12 @@ class I18n {
this
.
messages
[
this
.
locale
]
=
{};
}
this
.
message
=
this
.
messages
[
this
.
locale
];
this
.
watchers
.
forEach
((
watcher
)
=>
{
watcher
(
this
.
locale
,
oldLocale
);
});
// 仅发生变化时,通知
if
(
oldLocale
!==
this
.
locale
)
{
this
.
watchers
.
forEach
((
watcher
)
=>
{
watcher
(
this
.
locale
,
oldLocale
);
});
}
}
getLocale
()
{
return
this
.
locale
;
...
...
@@ -283,6 +288,9 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_
add
(
locale
,
message
)
{
return
i18n
.
add
(
locale
,
message
);
},
watch
(
fn
)
{
return
i18n
.
watchLocale
(
fn
);
},
getLocale
()
{
return
i18n
.
getLocale
();
},
...
...
@@ -292,6 +300,111 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_
};
}
const
isString
=
(
val
)
=>
typeof
val
===
'
string
'
;
let
formater
;
function
hasI18nJson
(
jsonObj
,
delimiters
)
{
if
(
!
formater
)
{
formater
=
new
BaseFormatter
();
}
return
walkJsonObj
(
jsonObj
,
(
jsonObj
,
key
)
=>
{
const
value
=
jsonObj
[
key
];
if
(
isString
(
value
))
{
if
(
isI18nStr
(
value
,
delimiters
))
{
return
true
;
}
}
else
{
return
hasI18nJson
(
value
,
delimiters
);
}
});
}
function
parseI18nJson
(
jsonObj
,
values
,
delimiters
)
{
if
(
!
formater
)
{
formater
=
new
BaseFormatter
();
}
walkJsonObj
(
jsonObj
,
(
jsonObj
,
key
)
=>
{
const
value
=
jsonObj
[
key
];
if
(
isString
(
value
))
{
if
(
isI18nStr
(
value
,
delimiters
))
{
jsonObj
[
key
]
=
compileStr
(
value
,
values
,
delimiters
);
}
}
else
{
parseI18nJson
(
value
,
values
,
delimiters
);
}
});
return
jsonObj
;
}
function
compileI18nJsonStr
(
jsonStr
,
{
locale
,
locales
,
delimiters
,
})
{
if
(
!
isI18nStr
(
jsonStr
,
delimiters
))
{
return
jsonStr
;
}
if
(
!
formater
)
{
formater
=
new
BaseFormatter
();
}
const
localeValues
=
[];
Object
.
keys
(
locales
).
forEach
((
name
)
=>
{
if
(
name
!==
locale
)
{
localeValues
.
push
({
locale
:
name
,
values
:
locales
[
name
],
});
}
});
localeValues
.
unshift
({
locale
,
values
:
locales
[
locale
]
});
try
{
return
JSON
.
stringify
(
compileJsonObj
(
JSON
.
parse
(
jsonStr
),
localeValues
,
delimiters
),
null
,
2
);
}
catch
(
e
)
{
}
return
jsonStr
;
}
function
isI18nStr
(
value
,
delimiters
)
{
return
value
.
indexOf
(
delimiters
[
0
])
>
-
1
;
}
function
compileStr
(
value
,
values
,
delimiters
)
{
return
formater
.
interpolate
(
value
,
values
,
delimiters
).
join
(
''
);
}
function
compileValue
(
jsonObj
,
key
,
localeValues
,
delimiters
)
{
const
value
=
jsonObj
[
key
];
if
(
isString
(
value
))
{
// 存在国际化
if
(
isI18nStr
(
value
,
delimiters
))
{
jsonObj
[
key
]
=
compileStr
(
value
,
localeValues
[
0
].
values
,
delimiters
);
// 格式化国际化语言
const
valueLocales
=
(
jsonObj
[
key
+
'
Locales
'
]
=
{});
localeValues
.
forEach
((
localValue
)
=>
{
valueLocales
[
localValue
.
locale
]
=
compileStr
(
value
,
localValue
.
values
,
delimiters
);
});
}
}
else
{
compileJsonObj
(
value
,
localeValues
,
delimiters
);
}
}
function
compileJsonObj
(
jsonObj
,
localeValues
,
delimiters
)
{
walkJsonObj
(
jsonObj
,
(
jsonObj
,
key
)
=>
{
compileValue
(
jsonObj
,
key
,
localeValues
,
delimiters
);
});
return
jsonObj
;
}
function
walkJsonObj
(
jsonObj
,
walk
)
{
if
(
isArray
(
jsonObj
))
{
for
(
let
i
=
0
;
i
<
jsonObj
.
length
;
i
++
)
{
if
(
walk
(
jsonObj
,
i
))
{
return
true
;
}
}
}
else
if
(
isObject
(
jsonObj
))
{
for
(
const
key
in
jsonObj
)
{
if
(
walk
(
jsonObj
,
key
))
{
return
true
;
}
}
}
return
false
;
}
exports
.
Formatter
=
BaseFormatter
;
exports
.
I18n
=
I18n
;
exports
.
LOCALE_EN
=
LOCALE_EN
;
...
...
@@ -299,4 +412,8 @@ exports.LOCALE_ES = LOCALE_ES;
exports
.
LOCALE_FR
=
LOCALE_FR
;
exports
.
LOCALE_ZH_HANS
=
LOCALE_ZH_HANS
;
exports
.
LOCALE_ZH_HANT
=
LOCALE_ZH_HANT
;
exports
.
compileI18nJsonStr
=
compileI18nJsonStr
;
exports
.
hasI18nJson
=
hasI18nJson
;
exports
.
initVueI18n
=
initVueI18n
;
exports
.
isString
=
isString
;
exports
.
parseI18nJson
=
parseI18nJson
;
packages/uni-i18n/dist/uni-i18n.d.ts
浏览文件 @
9dc717e3
export
declare
type
BuiltInLocale
=
typeof
LOCALE_ZH_HANS
|
typeof
LOCALE_ZH_HANT
|
typeof
LOCALE_EN
|
typeof
LOCALE_FR
|
typeof
LOCALE_ES
;
export
declare
function
compileI18nJsonStr
(
jsonStr
:
string
,
{
locale
,
locales
,
delimiters
,
}:
{
locale
:
string
;
locales
:
Record
<
string
,
Record
<
string
,
string
>>
;
delimiters
:
[
string
,
string
];
}):
string
;
export
declare
class
Formatter
{
_caches
:
{
[
key
:
string
]:
Array
<
Token
>
;
};
constructor
();
interpolate
(
message
:
string
,
values
?:
Record
<
string
,
unknown
>
|
Array
<
unknown
>
):
Array
<
unknown
>
;
interpolate
(
message
:
string
,
values
?:
Record
<
string
,
unknown
>
|
Array
<
unknown
>
,
delimiters
?:
[
string
,
string
]
):
Array
<
unknown
>
;
}
declare
interface
Formatter_2
{
interpolate
:
(
message
:
string
,
values
?:
Record
<
string
,
unknown
>
|
Array
<
unknown
>
)
=>
Array
<
unknown
>
;
interpolate
:
(
message
:
string
,
values
?:
Record
<
string
,
unknown
>
|
Array
<
unknown
>
,
delimiters
?:
[
string
,
string
]
)
=>
Array
<
unknown
>
;
}
export
declare
function
hasI18nJson
(
jsonObj
:
unknown
,
delimiters
:
[
string
,
string
]):
boolean
;
export
declare
class
I18n
{
private
locale
;
private
fallbackLocale
;
...
...
@@ -40,10 +48,13 @@ export declare function initVueI18n(locale?: BuiltInLocale, messages?: LocaleMes
i18n
:
I18n
;
t
(
key
:
string
,
values
?:
Record
<
string
,
unknown
>
|
unknown
[]
|
undefined
):
string
;
add
(
locale
:
BuiltInLocale
,
message
:
Record
<
string
,
string
>
):
void
;
watch
(
fn
:
LocaleWatcher
):
()
=>
void
;
getLocale
():
BuiltInLocale
;
setLocale
(
newLocale
:
BuiltInLocale
):
void
;
};
export
declare
const
isString
:
(
val
:
unknown
)
=>
val
is
string
;
export
declare
const
LOCALE_EN
=
"
en
"
;
export
declare
const
LOCALE_ES
=
"
es
"
;
...
...
@@ -60,6 +71,8 @@ export declare type LocaleMessages = {
export
declare
type
LocaleWatcher
=
(
newLocale
:
BuiltInLocale
,
oldLocale
:
BuiltInLocale
)
=>
void
;
export
declare
function
parseI18nJson
(
jsonObj
:
unknown
,
values
:
Record
<
string
,
string
>
,
delimiters
:
[
string
,
string
]):
unknown
;
declare
type
Token
=
{
type
:
'
text
'
|
'
named
'
|
'
list
'
|
'
unknown
'
;
value
:
string
;
...
...
packages/uni-i18n/dist/uni-i18n.es.js
浏览文件 @
9dc717e3
const
isArray
=
Array
.
isArray
;
const
isObject
=
(
val
)
=>
val
!==
null
&&
typeof
val
===
'
object
'
;
const
defaultDelimiters
=
[
'
{
'
,
'
}
'
];
class
BaseFormatter
{
constructor
()
{
this
.
_caches
=
Object
.
create
(
null
);
}
interpolate
(
message
,
values
)
{
interpolate
(
message
,
values
,
delimiters
=
defaultDelimiters
)
{
if
(
!
values
)
{
return
[
message
];
}
let
tokens
=
this
.
_caches
[
message
];
if
(
!
tokens
)
{
tokens
=
parse
(
message
);
tokens
=
parse
(
message
,
delimiters
);
this
.
_caches
[
message
]
=
tokens
;
}
return
compile
(
tokens
,
values
);
...
...
@@ -17,24 +19,24 @@ class BaseFormatter {
}
const
RE_TOKEN_LIST_VALUE
=
/^
(?:\d)
+/
;
const
RE_TOKEN_NAMED_VALUE
=
/^
(?:\w)
+/
;
function
parse
(
format
)
{
function
parse
(
format
,
[
startDelimiter
,
endDelimiter
]
)
{
const
tokens
=
[];
let
position
=
0
;
let
text
=
''
;
while
(
position
<
format
.
length
)
{
let
char
=
format
[
position
++
];
if
(
char
===
'
{
'
)
{
if
(
char
===
startDelimiter
)
{
if
(
text
)
{
tokens
.
push
({
type
:
'
text
'
,
value
:
text
});
}
text
=
''
;
let
sub
=
''
;
char
=
format
[
position
++
];
while
(
char
!==
undefined
&&
char
!==
'
}
'
)
{
while
(
char
!==
undefined
&&
char
!==
endDelimiter
)
{
sub
+=
char
;
char
=
format
[
position
++
];
}
const
isClosed
=
char
===
'
}
'
;
const
isClosed
=
char
===
endDelimiter
;
const
type
=
RE_TOKEN_LIST_VALUE
.
test
(
sub
)
?
'
list
'
:
isClosed
&&
RE_TOKEN_NAMED_VALUE
.
test
(
sub
)
...
...
@@ -42,12 +44,12 @@ function parse(format) {
:
'
unknown
'
;
tokens
.
push
({
value
:
sub
,
type
});
}
else
if
(
char
===
'
%
'
)
{
// when found rails i18n syntax, skip text capture
if
(
format
[
position
]
!==
'
{
'
)
{
text
+=
char
;
}
}
//
else if (char === '%') {
//
// when found rails i18n syntax, skip text capture
//
if (format[position] !== '{') {
// text += char
//
}
//
}
else
{
text
+=
char
;
}
...
...
@@ -58,7 +60,7 @@ function parse(format) {
function
compile
(
tokens
,
values
)
{
const
compiled
=
[];
let
index
=
0
;
const
mode
=
Array
.
isArray
(
values
)
const
mode
=
isArray
(
values
)
?
'
list
'
:
isObject
(
values
)
?
'
named
'
...
...
@@ -161,9 +163,12 @@ class I18n {
this
.
messages
[
this
.
locale
]
=
{};
}
this
.
message
=
this
.
messages
[
this
.
locale
];
this
.
watchers
.
forEach
((
watcher
)
=>
{
watcher
(
this
.
locale
,
oldLocale
);
});
// 仅发生变化时,通知
if
(
oldLocale
!==
this
.
locale
)
{
this
.
watchers
.
forEach
((
watcher
)
=>
{
watcher
(
this
.
locale
,
oldLocale
);
});
}
}
getLocale
()
{
return
this
.
locale
;
...
...
@@ -279,6 +284,9 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_
add
(
locale
,
message
)
{
return
i18n
.
add
(
locale
,
message
);
},
watch
(
fn
)
{
return
i18n
.
watchLocale
(
fn
);
},
getLocale
()
{
return
i18n
.
getLocale
();
},
...
...
@@ -288,4 +296,109 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_
};
}
export
{
BaseFormatter
as
Formatter
,
I18n
,
LOCALE_EN
,
LOCALE_ES
,
LOCALE_FR
,
LOCALE_ZH_HANS
,
LOCALE_ZH_HANT
,
initVueI18n
};
const
isString
=
(
val
)
=>
typeof
val
===
'
string
'
;
let
formater
;
function
hasI18nJson
(
jsonObj
,
delimiters
)
{
if
(
!
formater
)
{
formater
=
new
BaseFormatter
();
}
return
walkJsonObj
(
jsonObj
,
(
jsonObj
,
key
)
=>
{
const
value
=
jsonObj
[
key
];
if
(
isString
(
value
))
{
if
(
isI18nStr
(
value
,
delimiters
))
{
return
true
;
}
}
else
{
return
hasI18nJson
(
value
,
delimiters
);
}
});
}
function
parseI18nJson
(
jsonObj
,
values
,
delimiters
)
{
if
(
!
formater
)
{
formater
=
new
BaseFormatter
();
}
walkJsonObj
(
jsonObj
,
(
jsonObj
,
key
)
=>
{
const
value
=
jsonObj
[
key
];
if
(
isString
(
value
))
{
if
(
isI18nStr
(
value
,
delimiters
))
{
jsonObj
[
key
]
=
compileStr
(
value
,
values
,
delimiters
);
}
}
else
{
parseI18nJson
(
value
,
values
,
delimiters
);
}
});
return
jsonObj
;
}
function
compileI18nJsonStr
(
jsonStr
,
{
locale
,
locales
,
delimiters
,
})
{
if
(
!
isI18nStr
(
jsonStr
,
delimiters
))
{
return
jsonStr
;
}
if
(
!
formater
)
{
formater
=
new
BaseFormatter
();
}
const
localeValues
=
[];
Object
.
keys
(
locales
).
forEach
((
name
)
=>
{
if
(
name
!==
locale
)
{
localeValues
.
push
({
locale
:
name
,
values
:
locales
[
name
],
});
}
});
localeValues
.
unshift
({
locale
,
values
:
locales
[
locale
]
});
try
{
return
JSON
.
stringify
(
compileJsonObj
(
JSON
.
parse
(
jsonStr
),
localeValues
,
delimiters
),
null
,
2
);
}
catch
(
e
)
{
}
return
jsonStr
;
}
function
isI18nStr
(
value
,
delimiters
)
{
return
value
.
indexOf
(
delimiters
[
0
])
>
-
1
;
}
function
compileStr
(
value
,
values
,
delimiters
)
{
return
formater
.
interpolate
(
value
,
values
,
delimiters
).
join
(
''
);
}
function
compileValue
(
jsonObj
,
key
,
localeValues
,
delimiters
)
{
const
value
=
jsonObj
[
key
];
if
(
isString
(
value
))
{
// 存在国际化
if
(
isI18nStr
(
value
,
delimiters
))
{
jsonObj
[
key
]
=
compileStr
(
value
,
localeValues
[
0
].
values
,
delimiters
);
// 格式化国际化语言
const
valueLocales
=
(
jsonObj
[
key
+
'
Locales
'
]
=
{});
localeValues
.
forEach
((
localValue
)
=>
{
valueLocales
[
localValue
.
locale
]
=
compileStr
(
value
,
localValue
.
values
,
delimiters
);
});
}
}
else
{
compileJsonObj
(
value
,
localeValues
,
delimiters
);
}
}
function
compileJsonObj
(
jsonObj
,
localeValues
,
delimiters
)
{
walkJsonObj
(
jsonObj
,
(
jsonObj
,
key
)
=>
{
compileValue
(
jsonObj
,
key
,
localeValues
,
delimiters
);
});
return
jsonObj
;
}
function
walkJsonObj
(
jsonObj
,
walk
)
{
if
(
isArray
(
jsonObj
))
{
for
(
let
i
=
0
;
i
<
jsonObj
.
length
;
i
++
)
{
if
(
walk
(
jsonObj
,
i
))
{
return
true
;
}
}
}
else
if
(
isObject
(
jsonObj
))
{
for
(
const
key
in
jsonObj
)
{
if
(
walk
(
jsonObj
,
key
))
{
return
true
;
}
}
}
return
false
;
}
export
{
BaseFormatter
as
Formatter
,
I18n
,
LOCALE_EN
,
LOCALE_ES
,
LOCALE_FR
,
LOCALE_ZH_HANS
,
LOCALE_ZH_HANT
,
compileI18nJsonStr
,
hasI18nJson
,
initVueI18n
,
isString
,
parseI18nJson
};
packages/uni-i18n/src/I18n.ts
浏览文件 @
9dc717e3
...
...
@@ -21,7 +21,8 @@ export type LocaleMessages = {
export
interface
Formatter
{
interpolate
:
(
message
:
string
,
values
?:
Record
<
string
,
unknown
>
|
Array
<
unknown
>
values
?:
Record
<
string
,
unknown
>
|
Array
<
unknown
>
,
delimiters
?:
[
string
,
string
]
)
=>
Array
<
unknown
>
}
...
...
@@ -113,9 +114,12 @@ export class I18n {
this
.
messages
[
this
.
locale
]
=
{}
}
this
.
message
=
this
.
messages
[
this
.
locale
]
!
this
.
watchers
.
forEach
((
watcher
)
=>
{
watcher
(
this
.
locale
,
oldLocale
)
})
// 仅发生变化时,通知
if
(
oldLocale
!==
this
.
locale
)
{
this
.
watchers
.
forEach
((
watcher
)
=>
{
watcher
(
this
.
locale
,
oldLocale
)
})
}
}
getLocale
()
{
return
this
.
locale
...
...
packages/uni-i18n/src/format.ts
浏览文件 @
9dc717e3
const
isObject
=
(
val
:
unknown
):
val
is
Record
<
any
,
any
>
=>
export
const
isArray
=
Array
.
isArray
export
const
isObject
=
(
val
:
unknown
):
val
is
Record
<
any
,
any
>
=>
val
!==
null
&&
typeof
val
===
'
object
'
export
const
defaultDelimiters
:
[
string
,
string
]
=
[
'
{
'
,
'
}
'
]
export
default
class
BaseFormatter
{
_caches
:
{
[
key
:
string
]:
Array
<
Token
>
}
...
...
@@ -10,14 +12,15 @@ export default class BaseFormatter {
interpolate
(
message
:
string
,
values
?:
Record
<
string
,
unknown
>
|
Array
<
unknown
>
values
?:
Record
<
string
,
unknown
>
|
Array
<
unknown
>
,
delimiters
:
[
string
,
string
]
=
defaultDelimiters
):
Array
<
unknown
>
{
if
(
!
values
)
{
return
[
message
]
}
let
tokens
:
Array
<
Token
>
=
this
.
_caches
[
message
]
if
(
!
tokens
)
{
tokens
=
parse
(
message
)
tokens
=
parse
(
message
,
delimiters
)
this
.
_caches
[
message
]
=
tokens
}
return
compile
(
tokens
,
values
)
...
...
@@ -32,14 +35,17 @@ type Token = {
const
RE_TOKEN_LIST_VALUE
:
RegExp
=
/^
(?:\d)
+/
const
RE_TOKEN_NAMED_VALUE
:
RegExp
=
/^
(?:\w)
+/
export
function
parse
(
format
:
string
):
Array
<
Token
>
{
export
function
parse
(
format
:
string
,
[
startDelimiter
,
endDelimiter
]:
[
string
,
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
(
char
===
startDelimiter
)
{
if
(
text
)
{
tokens
.
push
({
type
:
'
text
'
,
value
:
text
})
}
...
...
@@ -47,11 +53,11 @@ export function parse(format: string): Array<Token> {
text
=
''
let
sub
:
string
=
''
char
=
format
[
position
++
]
while
(
char
!==
undefined
&&
char
!==
'
}
'
)
{
while
(
char
!==
undefined
&&
char
!==
endDelimiter
)
{
sub
+=
char
char
=
format
[
position
++
]
}
const
isClosed
=
char
===
'
}
'
const
isClosed
=
char
===
endDelimiter
const
type
=
RE_TOKEN_LIST_VALUE
.
test
(
sub
)
?
'
list
'
...
...
@@ -59,12 +65,14 @@ export function parse(format: string): Array<Token> {
?
'
named
'
:
'
unknown
'
tokens
.
push
({
value
:
sub
,
type
})
}
else
if
(
char
===
'
%
'
)
{
// when found rails i18n syntax, skip text capture
if
(
format
[
position
]
!==
'
{
'
)
{
text
+=
char
}
}
else
{
}
// else if (char === '%') {
// // when found rails i18n syntax, skip text capture
// if (format[position] !== '{') {
// text += char
// }
// }
else
{
text
+=
char
}
}
...
...
@@ -81,7 +89,7 @@ export function compile(
const
compiled
:
Array
<
unknown
>
=
[]
let
index
:
number
=
0
const
mode
:
string
=
Array
.
isArray
(
values
)
const
mode
:
string
=
isArray
(
values
)
?
'
list
'
:
isObject
(
values
)
?
'
named
'
...
...
packages/uni-i18n/src/index.ts
浏览文件 @
9dc717e3
export
*
from
'
./I18n
'
export
*
from
'
./vue-i18n
'
export
*
from
'
./json
'
export
{
default
as
Formatter
}
from
'
./format
'
packages/uni-i18n/src/json.ts
0 → 100644
浏览文件 @
9dc717e3
import
{
isArray
,
isObject
,
default
as
BaseFormatter
}
from
'
./format
'
import
{
Formatter
}
from
'
./I18n
'
export
const
isString
=
(
val
:
unknown
):
val
is
string
=>
typeof
val
===
'
string
'
let
formater
:
Formatter
|
null
interface
LocaleValue
{
locale
:
string
values
:
Record
<
string
,
unknown
>
}
type
LocaleValues
=
LocaleValue
[]
export
function
hasI18nJson
(
jsonObj
:
unknown
,
delimiters
:
[
string
,
string
]
):
boolean
{
if
(
!
formater
)
{
formater
=
new
BaseFormatter
()
}
return
walkJsonObj
(
jsonObj
,
(
jsonObj
,
key
)
=>
{
const
value
=
(
jsonObj
as
Record
<
string
|
number
,
unknown
>
)[
key
]
if
(
isString
(
value
))
{
if
(
isI18nStr
(
value
,
delimiters
))
{
return
true
}
}
else
{
return
hasI18nJson
(
value
,
delimiters
)
}
})
}
export
function
parseI18nJson
(
jsonObj
:
unknown
,
values
:
Record
<
string
,
string
>
,
delimiters
:
[
string
,
string
]
)
{
if
(
!
formater
)
{
formater
=
new
BaseFormatter
()
}
walkJsonObj
(
jsonObj
,
(
jsonObj
,
key
)
=>
{
const
value
=
(
jsonObj
as
Record
<
string
|
number
,
unknown
>
)[
key
]
if
(
isString
(
value
))
{
if
(
isI18nStr
(
value
,
delimiters
))
{
;(
jsonObj
as
Record
<
string
|
number
,
unknown
>
)[
key
]
=
compileStr
(
value
,
values
,
delimiters
)
}
}
else
{
parseI18nJson
(
value
,
values
,
delimiters
)
}
})
return
jsonObj
}
export
function
compileI18nJsonStr
(
jsonStr
:
string
,
{
locale
,
locales
,
delimiters
,
}:
{
locale
:
string
locales
:
Record
<
string
,
Record
<
string
,
string
>>
delimiters
:
[
string
,
string
]
}
)
{
if
(
!
isI18nStr
(
jsonStr
,
delimiters
))
{
return
jsonStr
}
if
(
!
formater
)
{
formater
=
new
BaseFormatter
()
}
const
localeValues
:
LocaleValues
=
[]
Object
.
keys
(
locales
).
forEach
((
name
)
=>
{
if
(
name
!==
locale
)
{
localeValues
.
push
({
locale
:
name
,
values
:
locales
[
name
],
})
}
})
localeValues
.
unshift
({
locale
,
values
:
locales
[
locale
]
})
try
{
return
JSON
.
stringify
(
compileJsonObj
(
JSON
.
parse
(
jsonStr
),
localeValues
,
delimiters
),
null
,
2
)
}
catch
(
e
)
{}
return
jsonStr
}
function
isI18nStr
(
value
:
string
,
delimiters
:
[
string
,
string
])
{
return
value
.
indexOf
(
delimiters
[
0
])
>
-
1
}
function
compileStr
(
value
:
string
,
values
:
LocaleValue
[
'
values
'
],
delimiters
:
[
string
,
string
]
)
{
return
formater
!
.
interpolate
(
value
,
values
,
delimiters
).
join
(
''
)
}
function
compileValue
(
jsonObj
:
Record
<
string
,
unknown
>
|
unknown
[],
key
:
string
|
number
,
localeValues
:
LocaleValues
,
delimiters
:
[
string
,
string
]
)
{
const
value
=
(
jsonObj
as
Record
<
string
|
number
,
unknown
>
)[
key
]
if
(
isString
(
value
))
{
// 存在国际化
if
(
isI18nStr
(
value
,
delimiters
))
{
// 格式化默认语言
;(
jsonObj
as
Record
<
string
|
number
,
unknown
>
)[
key
]
=
compileStr
(
value
,
localeValues
[
0
].
values
,
delimiters
)
// 格式化国际化语言
const
valueLocales
:
Record
<
string
,
string
>
=
((
jsonObj
as
Record
<
string
|
number
,
unknown
>
)[
key
+
'
Locales
'
]
=
{})
localeValues
.
forEach
((
localValue
)
=>
{
valueLocales
[
localValue
.
locale
]
=
compileStr
(
value
,
localValue
.
values
,
delimiters
)
})
}
}
else
{
compileJsonObj
(
value
,
localeValues
,
delimiters
)
}
}
function
compileJsonObj
(
jsonObj
:
unknown
,
localeValues
:
LocaleValues
,
delimiters
:
[
string
,
string
]
)
{
walkJsonObj
(
jsonObj
,
(
jsonObj
,
key
)
=>
{
compileValue
(
jsonObj
,
key
,
localeValues
,
delimiters
)
})
return
jsonObj
}
type
WalkJson
=
(
jsonObj
:
unknown
[]
|
Record
<
string
,
unknown
>
,
key
:
number
|
string
)
=>
void
|
boolean
function
walkJsonObj
(
jsonObj
:
unknown
,
walk
:
WalkJson
)
{
if
(
isArray
(
jsonObj
))
{
for
(
let
i
=
0
;
i
<
jsonObj
.
length
;
i
++
)
{
if
(
walk
(
jsonObj
,
i
))
{
return
true
}
}
}
else
if
(
isObject
(
jsonObj
))
{
for
(
const
key
in
jsonObj
)
{
if
(
walk
(
jsonObj
,
key
))
{
return
true
}
}
}
return
false
}
packages/uni-i18n/src/vue-i18n.ts
浏览文件 @
9dc717e3
import
{
I18n
,
BuiltInLocale
,
LocaleMessages
,
LOCALE_EN
}
from
'
./I18n
'
import
{
I18n
,
BuiltInLocale
,
LocaleMessages
,
LOCALE_EN
,
LocaleWatcher
,
}
from
'
./I18n
'
const
ignoreVueI18n
=
true
...
...
@@ -95,6 +101,9 @@ export function initVueI18n(
add
(
locale
:
BuiltInLocale
,
message
:
Record
<
string
,
string
>
)
{
return
i18n
.
add
(
locale
,
message
)
},
watch
(
fn
:
LocaleWatcher
)
{
return
i18n
.
watchLocale
(
fn
)
},
getLocale
()
{
return
i18n
.
getLocale
()
},
...
...
packages/uni-shared/dist/uni-shared.cjs.js
浏览文件 @
9dc717e3
...
...
@@ -948,6 +948,7 @@ const TABBAR_HEIGHT = 50;
const
ON_REACH_BOTTOM_DISTANCE
=
50
;
const
RESPONSIVE_MIN_WIDTH
=
768
;
const
COMPONENT_NAME_PREFIX
=
'
VUni
'
;
const
I18N_JSON_DELIMITERS
=
[
'
%
'
,
'
%
'
];
const
PRIMARY_COLOR
=
'
#007aff
'
;
const
SELECTED_COLOR
=
'
#0062cc
'
;
// 选中的颜色,如选项卡默认的选中颜色
const
BACKGROUND_COLOR
=
'
#f7f7f7
'
;
// 背景色,如标题栏默认背景色
...
...
@@ -1134,6 +1135,7 @@ exports.COMPONENT_SELECTOR_PREFIX = COMPONENT_SELECTOR_PREFIX;
exports
.
DATA_RE
=
DATA_RE
;
exports
.
EventChannel
=
EventChannel
;
exports
.
EventModifierFlags
=
EventModifierFlags
;
exports
.
I18N_JSON_DELIMITERS
=
I18N_JSON_DELIMITERS
;
exports
.
JSON_PROTOCOL
=
JSON_PROTOCOL
;
exports
.
NAVBAR_HEIGHT
=
NAVBAR_HEIGHT
;
exports
.
NODE_TYPE_COMMENT
=
NODE_TYPE_COMMENT
;
...
...
packages/uni-shared/dist/uni-shared.d.ts
浏览文件 @
9dc717e3
...
...
@@ -186,6 +186,8 @@ declare interface HTMLElementWithDataset extends HTMLElement {
__uniDataset
?:
Record
<
string
,
any
>
;
}
export
declare
const
I18N_JSON_DELIMITERS
:
[
string
,
string
];
export
declare
function
initCustomDataset
():
void
;
/**
...
...
packages/uni-shared/dist/uni-shared.es.js
浏览文件 @
9dc717e3
...
...
@@ -944,6 +944,7 @@ const TABBAR_HEIGHT = 50;
const
ON_REACH_BOTTOM_DISTANCE
=
50
;
const
RESPONSIVE_MIN_WIDTH
=
768
;
const
COMPONENT_NAME_PREFIX
=
'
VUni
'
;
const
I18N_JSON_DELIMITERS
=
[
'
%
'
,
'
%
'
];
const
PRIMARY_COLOR
=
'
#007aff
'
;
const
SELECTED_COLOR
=
'
#0062cc
'
;
// 选中的颜色,如选项卡默认的选中颜色
const
BACKGROUND_COLOR
=
'
#f7f7f7
'
;
// 背景色,如标题栏默认背景色
...
...
@@ -1101,4 +1102,4 @@ function getEnvLocale() {
return
(
lang
&&
lang
.
replace
(
/
[
.:
]
.*/
,
''
))
||
'
en
'
;
}
export
{
ACTION_TYPE_ADD_EVENT
,
ACTION_TYPE_ADD_WXS_EVENT
,
ACTION_TYPE_CREATE
,
ACTION_TYPE_EVENT
,
ACTION_TYPE_INSERT
,
ACTION_TYPE_PAGE_CREATE
,
ACTION_TYPE_PAGE_CREATED
,
ACTION_TYPE_PAGE_SCROLL
,
ACTION_TYPE_REMOVE
,
ACTION_TYPE_REMOVE_ATTRIBUTE
,
ACTION_TYPE_REMOVE_EVENT
,
ACTION_TYPE_SET_ATTRIBUTE
,
ACTION_TYPE_SET_TEXT
,
ATTR_CHANGE_PREFIX
,
ATTR_CLASS
,
ATTR_INNER_HTML
,
ATTR_STYLE
,
ATTR_TEXT_CONTENT
,
ATTR_V_OWNER_ID
,
ATTR_V_RENDERJS
,
ATTR_V_SHOW
,
BACKGROUND_COLOR
,
BUILT_IN_TAGS
,
COMPONENT_NAME_PREFIX
,
COMPONENT_PREFIX
,
COMPONENT_SELECTOR_PREFIX
,
DATA_RE
,
EventChannel
,
EventModifierFlags
,
JSON_PROTOCOL
,
NAVBAR_HEIGHT
,
NODE_TYPE_COMMENT
,
NODE_TYPE_ELEMENT
,
NODE_TYPE_PAGE
,
NODE_TYPE_TEXT
,
ON_ADD_TO_FAVORITES
,
ON_APP_ENTER_BACKGROUND
,
ON_APP_ENTER_FOREGROUND
,
ON_BACK_PRESS
,
ON_ERROR
,
ON_HIDE
,
ON_KEYBOARD_HEIGHT_CHANGE
,
ON_LAUNCH
,
ON_LOAD
,
ON_NAVIGATION_BAR_BUTTON_TAP
,
ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED
,
ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED
,
ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED
,
ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED
,
ON_PAGE_NOT_FOUND
,
ON_PAGE_SCROLL
,
ON_PULL_DOWN_REFRESH
,
ON_REACH_BOTTOM
,
ON_REACH_BOTTOM_DISTANCE
,
ON_READY
,
ON_RESIZE
,
ON_SHARE_APP_MESSAGE
,
ON_SHARE_TIMELINE
,
ON_SHOW
,
ON_TAB_ITEM_TAP
,
ON_THEME_CHANGE
,
ON_UNHANDLE_REJECTION
,
ON_UNLOAD
,
ON_WEB_INVOKE_APP_SERVICE
,
ON_WXS_INVOKE_CALL_METHOD
,
PLUS_RE
,
PRIMARY_COLOR
,
RENDERJS_MODULES
,
RESPONSIVE_MIN_WIDTH
,
SCHEME_RE
,
SELECTED_COLOR
,
TABBAR_HEIGHT
,
TAGS
,
UNI_SSR
,
UNI_SSR_DATA
,
UNI_SSR_GLOBAL_DATA
,
UNI_SSR_STORE
,
UNI_SSR_TITLE
,
UniBaseNode
,
UniCommentNode
,
UniElement
,
UniEvent
,
UniInputElement
,
UniLifecycleHooks
,
UniNode
,
UniTextAreaElement
,
UniTextNode
,
WEB_INVOKE_APPSERVICE
,
WXS_MODULES
,
WXS_PROTOCOL
,
addFont
,
cache
,
cacheStringFunction
,
callOptions
,
createRpx2Unit
,
createUniEvent
,
debounce
,
decode
,
decodedQuery
,
defaultRpx2Unit
,
formatAppLog
,
formatDateTime
,
formatLog
,
getCustomDataset
,
getEnvLocale
,
getLen
,
getValueByDataPath
,
initCustomDataset
,
invokeArrayFns
,
isBuiltInComponent
,
isCustomElement
,
isNativeTag
,
isRootHook
,
isServiceCustomElement
,
isServiceNativeTag
,
normalizeDataset
,
normalizeEventType
,
normalizeTarget
,
once
,
parseEventName
,
parseQuery
,
parseUrl
,
passive
,
plusReady
,
removeLeadingSlash
,
resolveOwnerEl
,
resolveOwnerVm
,
sanitise
,
scrollTo
,
stringifyQuery
,
updateElementStyle
};
export
{
ACTION_TYPE_ADD_EVENT
,
ACTION_TYPE_ADD_WXS_EVENT
,
ACTION_TYPE_CREATE
,
ACTION_TYPE_EVENT
,
ACTION_TYPE_INSERT
,
ACTION_TYPE_PAGE_CREATE
,
ACTION_TYPE_PAGE_CREATED
,
ACTION_TYPE_PAGE_SCROLL
,
ACTION_TYPE_REMOVE
,
ACTION_TYPE_REMOVE_ATTRIBUTE
,
ACTION_TYPE_REMOVE_EVENT
,
ACTION_TYPE_SET_ATTRIBUTE
,
ACTION_TYPE_SET_TEXT
,
ATTR_CHANGE_PREFIX
,
ATTR_CLASS
,
ATTR_INNER_HTML
,
ATTR_STYLE
,
ATTR_TEXT_CONTENT
,
ATTR_V_OWNER_ID
,
ATTR_V_RENDERJS
,
ATTR_V_SHOW
,
BACKGROUND_COLOR
,
BUILT_IN_TAGS
,
COMPONENT_NAME_PREFIX
,
COMPONENT_PREFIX
,
COMPONENT_SELECTOR_PREFIX
,
DATA_RE
,
EventChannel
,
EventModifierFlags
,
I18N_JSON_DELIMITERS
,
JSON_PROTOCOL
,
NAVBAR_HEIGHT
,
NODE_TYPE_COMMENT
,
NODE_TYPE_ELEMENT
,
NODE_TYPE_PAGE
,
NODE_TYPE_TEXT
,
ON_ADD_TO_FAVORITES
,
ON_APP_ENTER_BACKGROUND
,
ON_APP_ENTER_FOREGROUND
,
ON_BACK_PRESS
,
ON_ERROR
,
ON_HIDE
,
ON_KEYBOARD_HEIGHT_CHANGE
,
ON_LAUNCH
,
ON_LOAD
,
ON_NAVIGATION_BAR_BUTTON_TAP
,
ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED
,
ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED
,
ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED
,
ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED
,
ON_PAGE_NOT_FOUND
,
ON_PAGE_SCROLL
,
ON_PULL_DOWN_REFRESH
,
ON_REACH_BOTTOM
,
ON_REACH_BOTTOM_DISTANCE
,
ON_READY
,
ON_RESIZE
,
ON_SHARE_APP_MESSAGE
,
ON_SHARE_TIMELINE
,
ON_SHOW
,
ON_TAB_ITEM_TAP
,
ON_THEME_CHANGE
,
ON_UNHANDLE_REJECTION
,
ON_UNLOAD
,
ON_WEB_INVOKE_APP_SERVICE
,
ON_WXS_INVOKE_CALL_METHOD
,
PLUS_RE
,
PRIMARY_COLOR
,
RENDERJS_MODULES
,
RESPONSIVE_MIN_WIDTH
,
SCHEME_RE
,
SELECTED_COLOR
,
TABBAR_HEIGHT
,
TAGS
,
UNI_SSR
,
UNI_SSR_DATA
,
UNI_SSR_GLOBAL_DATA
,
UNI_SSR_STORE
,
UNI_SSR_TITLE
,
UniBaseNode
,
UniCommentNode
,
UniElement
,
UniEvent
,
UniInputElement
,
UniLifecycleHooks
,
UniNode
,
UniTextAreaElement
,
UniTextNode
,
WEB_INVOKE_APPSERVICE
,
WXS_MODULES
,
WXS_PROTOCOL
,
addFont
,
cache
,
cacheStringFunction
,
callOptions
,
createRpx2Unit
,
createUniEvent
,
debounce
,
decode
,
decodedQuery
,
defaultRpx2Unit
,
formatAppLog
,
formatDateTime
,
formatLog
,
getCustomDataset
,
getEnvLocale
,
getLen
,
getValueByDataPath
,
initCustomDataset
,
invokeArrayFns
,
isBuiltInComponent
,
isCustomElement
,
isNativeTag
,
isRootHook
,
isServiceCustomElement
,
isServiceNativeTag
,
normalizeDataset
,
normalizeEventType
,
normalizeTarget
,
once
,
parseEventName
,
parseQuery
,
parseUrl
,
passive
,
plusReady
,
removeLeadingSlash
,
resolveOwnerEl
,
resolveOwnerVm
,
sanitise
,
scrollTo
,
stringifyQuery
,
updateElementStyle
};
packages/uni-shared/src/constants.ts
浏览文件 @
9dc717e3
...
...
@@ -5,6 +5,8 @@ export const RESPONSIVE_MIN_WIDTH = 768
export
const
COMPONENT_NAME_PREFIX
=
'
VUni
'
export
const
I18N_JSON_DELIMITERS
:
[
string
,
string
]
=
[
'
%
'
,
'
%
'
]
export
const
PRIMARY_COLOR
=
'
#007aff
'
export
const
SELECTED_COLOR
=
'
#0062cc
'
// 选中的颜色,如选项卡默认的选中颜色
export
const
BACKGROUND_COLOR
=
'
#f7f7f7
'
// 背景色,如标题栏默认背景色
...
...
packages/uni-stat/dist/uni-stat.cjs.js
浏览文件 @
9dc717e3
'
use strict
'
;
var
version
=
"
3.0.0-alpha-300002021082700
3
"
;
var
version
=
"
3.0.0-alpha-300002021082700
4
"
;
const
STAT_VERSION
=
version
;
const
STAT_URL
=
'
https://tongji.dcloud.io/uni/stat
'
;
...
...
packages/uni-stat/dist/uni-stat.es.js
浏览文件 @
9dc717e3
var
version
=
"
3.0.0-alpha-300002021082700
3
"
;
var
version
=
"
3.0.0-alpha-300002021082700
4
"
;
const
STAT_VERSION
=
version
;
const
STAT_URL
=
'
https://tongji.dcloud.io/uni/stat
'
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录