* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
import { reactive, ref } from 'vue'
import { utils } from '@opentiny/tiny-engine-utils'
import { isVsCodeEnv } from '@opentiny/tiny-engine-common/js/environments'
import { constants } from '@opentiny/tiny-engine-utils'
import { generateI18n } from '@opentiny/tiny-engine-common/js/vscodeGenerateFile'
import { PROP_DATA_TYPE } from '@opentiny/tiny-engine-common/js/constants'
import { useResource, useCanvas, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
const { HOST_TYPE } = constants
const state = reactive<{ langs: Record<string, any> }>({
langs: {}
})
const currentLanguage = ref('zh_CN')
const i18nResource = reactive<{
messages: Record<string, any>
locales: any[]
[x: string]: any
}>({
messages: {},
locales: []
})
const i18nApi = '/app-center/api/i18n/entries'
const globalParams = {
host: '',
host_type: ''
}
const getLangs = () => state.langs
const setLangs = (newLangs = {}) => {
state.langs = newLangs
}
const removeI18n = (key = []) => {
if (!key.length) {
return
}
const langs = getLangs()
key.forEach((element) => {
delete langs[element]
})
getMetaApi(META_SERVICE.Http).post(`${i18nApi}/bulk/delete`, {
...globalParams,
key_in: key
})
}
*
* @param {Object} obj 国际化对象
* @param {Boolean} send 为true时表示需要向后台发起请求进行新增或修改
* @returns
*/
const ensureI18n = (obj: { [x: string]: any; key: string }, send?: boolean) => {
const { locales } = i18nResource
const contents = Object.fromEntries(locales.map(({ lang }) => [lang, obj[lang] || '']))
const langs = getLangs()
const key = obj.key || utils.guid()
if (send) {
const exist = langs[key]
if (globalParams.host) {
getMetaApi(META_SERVICE.Http).post(`${i18nApi}/${exist ? 'update' : 'create'}`, {
...globalParams,
key,
contents
})
}
locales.forEach((lang) => {
if (i18nResource[lang]?.[key]) {
i18nResource[lang][key] = contents[lang]
}
})
if (isVsCodeEnv) {
generateI18n({
key,
contents
})
}
}
try {
const messages: Record<string, any> = {}
Object.entries(contents).forEach(([locale, message]) => {
messages[locale] = {
[key]: message
}
})
useCanvas().canvasApi.value?.setLocales?.(messages, true)
} catch (e) {
}
langs[key] = { key, ...contents, type: PROP_DATA_TYPE.I18N }
return langs[key]
}
const getI18nData = () => {
return getMetaApi(META_SERVICE.Http).get(i18nApi, {
params: { ...globalParams, _limit: -1 }
})
}
export interface I18nOptions {
init?: boolean
local?: any
host?: string
hostType?: string
}
const getI18n = async ({ init, local }: I18nOptions): Promise<typeof appSchemaState.langs> => {
const { appSchemaState } = useResource()
if (local) {
const locales = appSchemaState?.langs?.locales || []
const messages: Record<string, any> = {}
const langs = getLangs()
if (Array.isArray(locales)) {
locales.forEach(({ lang }) => {
messages[lang] = {}
Object.entries(langs).forEach(([key, message]) => {
messages[lang][key] = message[lang]
})
})
}
return { locales, messages }
} else {
const i18n = init ? appSchemaState.langs : await getI18nData()
return i18n
}
}
const initI18n = async ({ host, hostType, init, local }: I18nOptions) => {
globalParams.host = host || ''
const hostTypeVar = 'host_type'
globalParams[hostTypeVar] = hostType || HOST_TYPE.App
const { locales = [], messages = {} } = await getI18n({ host, hostType, init, local })
const langs = locales.map((item) => item.lang)
const firstLangData = messages[langs[0] || 'zh_CN']
i18nResource.locales = locales
i18nResource.messages = messages
Object.keys(firstLangData || {}).forEach((key) => {
const i18n = { key }
langs.forEach((lang) => messages[lang] && Object.assign(i18n, { [lang]: messages[lang][key] }))
ensureI18n(i18n)
})
}
const initAppI18n = async (appId: string) => {
if (appId) {
await initI18n({
host: appId,
hostType: HOST_TYPE.App
})
useCanvas().canvasApi.value?.setLocales?.(i18nResource.messages)
}
}
const initBlockI18n = async (blockId: string) => {
if (blockId) {
await initI18n({
host: blockId,
hostType: HOST_TYPE.Block
})
useCanvas().canvasApi.value?.setLocales?.(i18nResource.messages)
}
}
const initBlockLocalI18n = async (langs = {}) => {
setLangs(langs)
await initI18n({
host: '',
hostType: HOST_TYPE.Block,
local: true
})
useCanvas().canvasApi.value?.setLocales?.(i18nResource.messages)
}
const format = (str = '', params: Record<string, any> = {}) =>
str.replace(/\$\{(.+?)\}/g, (_substr, key: string) => params[key] || '')
const translate = (obj: { [x: string]: any }) => {
const { type, key = utils.guid() } = obj || {}
if (type === PROP_DATA_TYPE.I18N) {
const langs = getLangs()
const i18n = langs[key]
const langData = i18n || obj
return format(langData[currentLanguage.value] || langData.key, obj.params)
}
return obj
}
const getData = () => i18nResource.messages
const batchCreateI18n = ({ host, hostType }: Pick<I18nOptions, 'host' | 'hostType'>) => {
if (!host) {
return
}
globalParams.host = host
globalParams.host_type = hostType || ''
const { locales } = i18nResource
const langs = getLangs()
const entries = Object.entries(langs).map(([key, message]) => ({
key,
contents: Object.fromEntries(locales.map(({ lang }) => [lang, message[lang]]))
}))
getMetaApi(META_SERVICE.Http).post(`${i18nApi}/batch/create`, {
...globalParams,
entries
})
}
export default () => {
return {
i18nResource,
currentLanguage,
getLangs,
setLangs,
getData,
translate,
removeI18n,
ensureI18n,
initI18n,
batchCreateI18n,
initAppI18n,
initBlockI18n,
getI18nData,
initBlockLocalI18n
}
}