Skip to content

国际化(i18n)支持 v0.5.0+

uView Pro 所有内置组件均支持多语言,支持全局与组件级配置、响应式切换与持久化语言偏好。

核心特性

  • 内置语言: 默认包含 zh-CNen-US
  • 配置灵活: 支持在应用入口全局配置或组件内覆盖局部语言包。
  • 响应式切换: 切换语言时组件文案自动更新。
  • 持久化: 用户选择会被保存以便下次恢复。
  • 扩展友好: 可按需添加或覆盖语言包,支持按需加载。

特别注意

组件库发布到 npm 的是未编译的 Vue 和 TypeScript 代码。由于 Vite 会预构建依赖到 node_modules/.vite,而国际化基于 reactive 实现数据共享,开发阶段可能导致页面使用预构建产物中的数据,而组件库使用内部数据,造成数据不同步。

uni_modules 模式下,需在 vite.config.ts 中添加配置排除预构建:

ts
import { defineConfig } from 'vite'

export default defineConfig({
    ...
    optimizeDeps: {
        exclude: process.env.UNI_PLATFORM === 'h5' && process.env.NODE_ENV === 'development' ? ['uview-pro'] : []
    }
    ...
})

uni_modules 模式无需额外处理。

快速上手

方式一:全局注册(main.ts):

ts
app.use(uViewPro, { locale: 'zh-CN' })

// 或
import { zhCN, enUS } from 'uview-pro/locale';

app.use(uViewPro, {
  locale: { locales: [zhCN, enUS], defaultLocale: 'zh-CN' }
})

方式二:使用 u-config-provideruseLocale() 在组件级提供 localescurrentLocale

vue
<template>
  <u-config-provider
    :locales="locales"
    :current-locale="currentLocale"
  >
    <!-- 你的应用内容 -->
    <u-modal v-model="show" :content="content"></u-modal> 
    <u-button @click="open"> 打开模态框 </u-button>
  </u-config-provider>
</template>

<script setup lang="ts">
import { useLocale } from 'uview-pro'

const { currentLocale, locales } = useLocale()
const show = ref<boolean>(false)
const content = ref<string>('东临碣石,以观沧海')

const open = () => {
    show.value = true
}
</script>
  • 编程式切换语言:
ts
import { useLocale } from 'uview-pro';

const { setLocale } = useLocale()
setLocale('en-US')

覆盖默认语言包

  • 局部覆盖:在 locale.locales 中传入部分字段,uView Pro 将与内置文案合并(深度覆盖)。
typescript
// main.ts
app.use(uViewPro, {
  theme: themes,
  locale: {
    locales: [{
      name: 'zh-CN',
      modal: {
        confirmText: '好的',  // 自定义确认按钮文案
        cancelText: '算了'   // 自定义取消按钮文案
      },
      upload: {
        uploadText: '选择文件'  // 自定义上传文案
      }
    }],
    defaultLocale: 'zh-CN'
  }
})

添加新语言包

  • 新增语言:创建语言文件(示例 src/locales/fr-FR.ts,包含 name 字段及组件文案),并在入口注册。所有字段见下方“语言包字段说明”章节。

假设我们要为应用添加法语支持:

typescript
// 首先创建法语语言包文件
// src/locales/fr-FR.ts
export default {
  name: 'fr-FR', // 必须要有
  uActionSheet: {
    cancelText: 'Annuler'
  },
  uModal: {
    title: 'Avertissement',
    content: 'Contenu',
    confirmText: 'Confirmer',
    cancelText: 'Annuler'
  },
  uCalendar: {
    startText: 'Début',
    endText: 'Fin',
    confirmText: 'Confirmer',
    toolTip: 'Sélectionner une date',
    // ... 其他法语翻译
  },
  uUpload: {
    uploadText: 'Sélectionner une image',
    retry: 'Réessayer',
    overSize: 'Le fichier dépasse la taille autorisée',
    // ... 更多法语文案
  },
  // ... 继续添加其他组件的法语翻译
}

注意

  1. 必须将 name 字段作为语言包的唯一标识。
  2. 新的语言包中必须包含所有字段,否则未存在的字段将会显示异常。

在入口注册时引入并添加该语言包:

typescript
// main.ts
import { createApp } from 'vue'
import uViewPro from 'uview-pro'
import frFR from './locales/fr-FR'

const app = createApp(App)

app.use(uViewPro, {
  theme: themes,
  locale: {
    locales: [frFR], // 添加法语语言包
    defaultLocale: 'fr-FR' // 设置默认语言为法语,为语言包中的name字段
  }
})

国际化 Hook 使用

  • Hook 使用:
ts
import { useLocale } from 'uview-pro';

const { t } = useLocale('uModal')
const text = t('confirmText') // 等价于 t('uModal.confirmText')

// 等价于
const { t } = useLocale();
const text = t('uModal.confirmText');
  • 动态参数替换:t('welcome', { name: '张三' }) → "欢迎您,张三!"

与 vue-i18n 集成

vue-i18n 官方文档

方案:使用 vue-i18n 管理业务文案,uView Pro 管理组件文案。

启动顺序建议先 app.use(i18n),再 app.use(uViewPro, { locale: { defaultLocale: ... } }),切换时同步两端语言即可。

1. 注册 vue-i18n 和 uView Pro

首先你应该在项目中配置vue-i18n:

typescript
// src/locales/index.ts
import { createI18n } from 'vue-i18n';

import zhCN from './langs/zh-CN.json'; // 简体中文
import enUS from './langs/en-US.json'; // 英文

const messages = {
  'zh-Hans': zhCN,
  en: enUS,
};

// 自动检测用户语言
const getDefaultLocale = () => {
  try {
    const lang = uni.getLocale?.() || 'zh-Hans';
    return lang.startsWith('zh') ? 'zh-Hans' : 'en';
  } catch {
    return 'zh-Hans';
  }
};

const i18n = createI18n({
  locale: getDefaultLocale(),
  fallbackLocale: 'zh-Hans',
  messages,
  allowComposition: true,
  legacy: false,
  globalInjection: true
});

export default i18n;

然后在main.ts中集成vue-i18n和uView Pro:

typescript
// main.ts
import { createSSRApp } from 'vue';
import App from './App.vue';
import i18n from './locales';
import uViewPro from 'uview-pro';

const app = createSSRApp(App);

// 先使用vue-i18n
app.use(i18n);

// 再使用uView Pro,并配置国际化
app.use(uViewPro, {
  locale: {
    // 设置 'zh-CN' 为默认语言
    defaultLocale: 'zh-CN'
  }
});

2. 语言切换

vue-i18nlocale 与 uView Pro 的 setLocale() 进行映射(如 zh-Hanszh-CN)。

ts
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useLocale } from 'uview-pro';

const { t, locale } = useI18n();
const { setLocale } = useLocale();

type LocaleKey = 'zh-Hans' | 'en';

const handleLocaleChange = (value: LocaleKey) => {
  // 设置vue-i18n语言
  locale.value = value;

  // 设置系统语言
  uni.setLocale(value);

  // 设置uView Pro语言
  const uViewLocale = value === 'zh-Hans' ? 'zh-CN' : 'en-US';
  setLocale(uViewLocale);
};

// 切换到英文
handleLocaleChange('en');
// 切换到中文
handleLocaleChange('zh-Hans');

常见 API 摘要

  • useLocale() → 返回 { t, setLocale, currentLocale, locales }
  • t(key, params?) → 获取翻译字符串并支持参数替换。
  • setLocale(name) → 切换语言(例如 zh-CN / en-US)。

uView Pro 的 i18n 旨在提供实用、可扩展且易集成的组件文案国际化能力。项目中建议用 vue-i18n 管理业务文案,uView Pro 管理组件文案,切换时同步即可。

语言包字段说明

uview Pro 默认支持 2 个语言包(中文、英文),更多语言包请自行添加,下述为所有字段:

ts
export default {
    name: 'zh-CN', // 必要
    label: '简体中文', // 必要
    locale: 'zh-Hans', // 必要
    uActionSheet: {
        cancelText: '取消'
    },
    uUpload: {
        uploadText: '选择图片',
        retry: '点击重试',
        overSize: '超出允许的文件大小',
        overMaxCount: '超出最大允许的文件个数',
        reUpload: '重新上传',
        uploadFailed: '上传失败,请重试',
        modalTitle: '提示',
        deleteConfirm: '您确定要删除此项吗?',
        terminatedRemove: '已终止移除',
        removeSuccess: '移除成功',
        previewFailed: '预览图片失败',
        notAllowedExt: '不允许选择{ext}格式的文件',
        noAction: '请配置上传地址'
    },
    uVerificationCode: {
        startText: '获取验证码',
        changeText: 'X秒重新获取',
        endText: '重新获取'
    },
    uSection: {
        subTitle: '更多'
    },
    uSelect: {
        cancelText: '取消',
        confirmText: '确认'
    },
    uSearch: {
        placeholder: '请输入关键字',
        actionText: '搜索'
    },
    uNoNetwork: {
        tips: '哎呀,网络信号丢失',
        checkNetwork: '请检查网络,或前往',
        setting: '设置',
        retry: '重试',
        noConnection: '无网络连接',
        connected: '网络已连接'
    },
    uReadMore: {
        closeText: '展开阅读全文',
        openText: '收起'
    },
    uPagination: {
        prevText: '上一页',
        nextText: '下一页'
    },
    uPicker: {
        cancelText: '取消',
        confirmText: '确认'
    },
    uModal: {
        title: '提示',
        content: '内容',
        confirmText: '确认',
        cancelText: '取消'
    },
    uLoadmore: {
        loadmore: '加载更多',
        loading: '正在加载...',
        nomore: '没有更多了'
    },
    uLink: {
        mpTips: '链接已复制,请在浏览器打开'
    },
    uKeyboard: {
        cancelText: '取消',
        confirmText: '确认',
        number: '数字键盘',
        idCard: '身份证键盘',
        plate: '车牌号键盘'
    },
    uInput: {
        placeholder: '请输入内容'
    },
    uCalendar: {
        startText: '开始',
        endText: '结束',
        toolTip: '选择日期',
        outOfRange: '日期超出范围啦~',
        year: '年',
        month: '月',
        sun: '日',
        mon: '一',
        tue: '二',
        wed: '三',
        thu: '四',
        fri: '五',
        sat: '六',
        confirmText: '确定',
        to: '至'
    },
    uEmpty: {
        car: '购物车为空',
        page: '页面不存在',
        search: '没有搜索结果',
        address: '没有收货地址',
        wifi: '没有WiFi',
        order: '订单为空',
        coupon: '没有优惠券',
        favor: '暂无收藏',
        permission: '无权限',
        history: '无历史记录',
        news: '无新闻列表',
        message: '消息列表为空',
        list: '列表为空',
        data: '数据为空'
    },
    uCountDown: {
        day: '天',
        hour: '时',
        minute: '分',
        second: '秒'
    },
    uFullScreen: {
        title: '发现新版本',
        upgrade: '升级'
    }
};
ts
export default {
    name: 'en-US', // 必要
    label: 'English', // 必要
    locale: 'en', // 必要
    uActionSheet: {
        cancelText: 'Cancel'
    },
    uUpload: {
        uploadText: 'Select Image',
        retry: 'Retry',
        overSize: 'File size exceeds allowed limit',
        overMaxCount: 'Exceeds maximum allowed number of files',
        reUpload: 'Re-upload',
        uploadFailed: 'Upload failed, please try again',
        modalTitle: 'Notice',
        deleteConfirm: 'Are you sure you want to delete this item?',
        terminatedRemove: 'Removal cancelled',
        removeSuccess: 'Removed successfully',
        previewFailed: 'Failed to preview image',
        notAllowedExt: 'Files with {ext} format are not allowed',
        noAction: 'Please configure upload address'
    },
    uVerificationCode: {
        startText: 'Get Code',
        changeText: 'Retry in Xs',
        endText: 'Retry'
    },
    uSection: {
        subTitle: 'More'
    },
    uSelect: {
        cancelText: 'Cancel',
        confirmText: 'Confirm'
    },
    uSearch: {
        placeholder: 'Please enter keywords',
        actionText: 'Search'
    },
    uNoNetwork: {
        tips: 'Ooops, network disconnected',
        checkNetwork: 'Please check network or go to',
        setting: 'Settings',
        retry: 'Retry',
        noConnection: 'No network connection',
        connected: 'Network connected'
    },
    uReadMore: {
        closeText: 'Read More',
        openText: 'Collapse'
    },
    uPagination: {
        prevText: 'Prev',
        nextText: 'Next'
    },
    uPicker: {
        cancelText: 'Cancel',
        confirmText: 'Confirm'
    },
    uModal: {
        title: 'Notice',
        content: 'Content',
        confirmText: 'Confirm',
        cancelText: 'Cancel'
    },
    uLoadmore: {
        loadmore: 'Load more',
        loading: 'Loading...',
        nomore: 'No more'
    },
    uLink: {
        mpTips: 'Link copied, please open it in browser'
    },
    uKeyboard: {
        cancelText: 'Cancel',
        confirmText: 'Confirm',
        number: 'Number Keyboard',
        idCard: 'ID Card Keyboard',
        plate: 'Plate Keyboard'
    },
    uInput: {
        placeholder: 'Please enter'
    },
    uCalendar: {
        startText: 'Start',
        endText: 'End',
        toolTip: 'Select date',
        outOfRange: 'Date out of range',
        year: '',
        month: '',
        sun: 'Sun',
        mon: 'Mon',
        tue: 'Tue',
        wed: 'Wed',
        thu: 'Thu',
        fri: 'Fri',
        sat: 'Sat',
        confirmText: 'Confirm',
        to: ' to '
    },
    uEmpty: {
        car: 'Shopping cart is empty',
        page: 'Page not found',
        search: 'No search results',
        address: 'No shipping address',
        wifi: 'No WiFi',
        order: 'No orders',
        coupon: 'No coupons',
        favor: 'No favorites',
        permission: 'No permission',
        history: 'No history',
        news: 'No news',
        message: 'No messages',
        list: 'No list',
        data: 'No data'
    },
    uCountDown: {
        day: 'days',
        hour: 'hours',
        minute: 'minutes',
        second: 'Second'
    },
    uFullScreen: {
        title: 'New Version Available',
        upgrade: 'Upgrade'
    }
};