npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-localeflow

v0.2.0

Published

A lightweight, type-safe Vue 3 internationalization (i18n) solution with reactive language switching and localStorage support

Readme

vue-localeflow

一个轻量级、类型安全的 Vue 3 国际化(i18n)解决方案,提供响应式的语言切换和本地存储支持。支持任意数据类型,包括字符串、对象、组件和函数。

English | 中文

✨ 特性

  • 🚀 轻量级 - 压缩后<1KB,不到 100 行代码
  • 💪 类型安全 - 完整的 TypeScript 支持,编译时类型检查
  • 高性能 - 无额外的函数调用开销,直接访问响应式对象
  • 💾 持久化 - 自动持久化多语言设置,刷新后保持语言选择
  • 🎯 简单易用 - 极简的 API 设计,三分钟上手
  • 🌍 多类型支持 - 支持字符串、对象、Vue 组件、函数等任意类型

📦 安装

# npm
npm install vue-localeflow

# yarn
yarn add vue-localeflow

# pnpm
pnpm add vue-localeflow

🚀 快速开始

基础用法

import { createLang } from 'vue-localeflow'

// 定义语言数据(支持任意类型)
const langData = {
  chs: {
    hello: '你好',
    country: {
      cn: '中国',
      us: '美国',
    },
  },
  en: {
    hello: 'Hello',
    country: {
      cn: 'China',
      us: 'United States',
    },
  },
}

// 创建语言管理器
const lang = createLang(langData, { default: 'chs' })

// 使用语言数据
console.log(lang.hello) // '你好'
console.log(lang.country.cn) // '中国'
console.log(lang.$.lang) // 'chs' (当前语言键)

// 切换语言
lang.$.set('en')
console.log(lang.hello) // 'Hello'
console.log(lang.country.cn) // 'China'

在 Vue 组件中使用

<template>
  <div>
    <!-- 语言切换按钮 -->
    <div class="lang-switcher">
      <button
        v-for="l in langs"
        :key="l.key"
        @click="lang.$.set(l.key)"
        :class="{ active: lang.$.lang === l.key }"
      >
        {{ l.label }}
      </button>
    </div>

    <!-- 直接访问语言数据 -->
    <h1>{{ lang.hello }}</h1>
    <p>{{ lang.country.cn }}</p>

    <!-- 当前语言显示 -->
    <p>当前语言:{{ lang.$.lang }}</p>
  </div>
</template>

<script setup lang="ts">
import { createLang } from 'vue-localeflow'

const langData = {
  chs: {
    hello: '你好,世界!',
    country: { cn: '中国', us: '美国' },
  },
  en: {
    hello: 'Hello, World!',
    country: { cn: 'China', us: 'United States' },
  },
  cht: {
    hello: '你好,世界!',
    country: { cn: '中國', us: '美國' },
  },
}

const lang = createLang(langData, { default: 'chs' })

const langs = [
  { key: 'chs', label: '简体中文' },
  { key: 'en', label: 'English' },
  { key: 'cht', label: '繁體中文' },
]
</script>

支持多种数据类型

import { createLang } from 'vue-localeflow'
import HelloComponent from './components/Hello.vue'

const lang = createLang({
  chs: {
    // 字符串
    title: '欢迎',
    // 嵌套对象
    country: {
      cn: '中国',
      us: '美国',
    },
    // Vue 组件
    helloUI: <HelloComponent country="cn" />,
    // 函数
    helloTo: (name: string) => `你好,${name}!`,
  },
  en: {
    title: 'Welcome',
    country: {
      cn: 'China',
      us: 'United States',
    },
    helloUI: <HelloComponent country="en" />,
    helloTo: (name: string) => `Hello, ${name}!`,
  },
})

// 使用不同类型的数据
console.log(lang.title) // 字符串
console.log(lang.country.cn) // 嵌套对象
console.log(lang.helloTo('Vue')) // 函数调用
// 在模板中使用组件:<component :is="lang.helloUI" />

使用 t 函数进行临时多语言映射

// t 函数用于一次性的多语言映射,无需预定义
const message = lang.$.t({
  chs: '中午好,你吃了吗?',
  en: 'Good afternoon, have you eaten?',
  cht: '中午好,你吃了嗎?',
})

// 根据当前语言返回对应的值
console.log(message) // 根据 lang.$.lang 返回对应语言的文本

📚 API 参考

createLang(langs, options?)

创建一个语言管理器实例。

参数

  • langs - 语言数据对象,键为语言标识,值为该语言的数据对象(支持任意类型)
  • options - 可选配置项
    • default - 默认语言键,如果未指定则使用 langs 中声明的第一个语言;如果传入了无效值,也会回退到第一个语言
    • storageKey - localStorage 存储键名,默认为 'vue-localeflow'
    • storage - 自定义持久化适配器,适合接入 Cookie 或其他存储介质
    • resolveInitialLang - 当没有持久化值时,用于决定初始语言的自定义函数

返回值

返回一个只读的响应式代理对象,包含以下属性和方法:

  • $ - 语言管理器对象,包含以下属性和方法:
    • lang - 当前激活的语言键(只读)
    • set(key, persist?) - 设置当前语言
      • key - 要设置的语言键
      • persist - 是否写入当前持久化适配器,默认为 true
    • t(options) - 根据当前语言动态选择值
      • options - 包含语言键对应值的对象,允许只传部分语言
      • 返回值 - 优先返回当前语言对应的值;如果缺失,则回退到 default 对应的值;如果仍然缺失,则按 langs 的声明顺序返回第一个可用值
  • ...langData - 当前语言的所有数据属性(通过 Proxy 动态代理访问)

🔧 高级用法

Nuxt SSR 接入

在 SPA 中无需额外配置,直接使用 createLang() 即可。

如果在 Nuxt 中使用,为了让服务端请求内的语言状态隔离生效,建议在 Nuxt 插件中接入 vue-localeflow/nuxt

// plugins/lang.ts
import { installNuxtLang } from 'vue-localeflow/nuxt'
import { lang } from '~/lang'

export default defineNuxtPlugin((nuxtApp) => {
  const cookie = useCookie<'chs' | 'en'>('lang')

  installNuxtLang(lang, nuxtApp.vueApp, {
    useState,
    storage: {
      get: () => cookie.value,
      set: (value) => {
        cookie.value = value
      },
    },
    resolveInitialLang: () => {
      if (import.meta.server) {
        const headers = useRequestHeaders(['accept-language'])
        const acceptLanguage = headers['accept-language'] || ''

        if (acceptLanguage.includes('zh')) return 'chs'
        if (acceptLanguage.includes('en')) return 'en'
        return undefined
      }

      return navigator.language.startsWith('zh') ? 'chs' : 'en'
    },
  })
})

如果你只是在 SPA 中根据浏览器语言初始化,可以直接在 createLang() 中传入 resolveInitialLang

const lang = createLang(langData, {
  default: 'en',
  resolveInitialLang: () => {
    if (navigator.language.startsWith('zh-CN')) return 'chs'
    if (navigator.language.startsWith('en')) return 'en'
    return undefined
  },
})

接入完成后,业务代码仍然可以继续全局导出并直接使用 lang

// 任意运行时调用链里都可以直接读取
export function getPageTitle() {
  return lang.title
}

不建议在模块顶层缓存请求态语言值,例如:

// 不推荐
export const pageTitle = lang.title

这类顶层求值会在 SSR 中丢失当前请求上下文。

TypeScript 类型安全

// 定义语言数据类型
const chs = {
  nav: {
    home: '首页',
    about: '关于我们',
    contact: '联系我们',
  },
  message: {
    welcome: '欢迎访问我们的网站!',
    error: '发生了错误',
  },
  format: {
    date: 'YYYY年MM月DD日',
    currency: '¥',
  },
} as const

export type ILang = typeof chs

// 其他语言必须符合同样的类型
const en: ILang = {
  nav: {
    home: 'Home',
    about: 'About Us',
    contact: 'Contact Us',
  },
  message: {
    welcome: 'Welcome to our website!',
    error: 'An error occurred',
  },
  format: {
    date: 'MM/DD/YYYY',
    currency: '$',
  },
}

export const lang = createLang({ chs, en }, { default: 'chs' })

// 现在享受完整的类型提示和检查
console.log(lang.nav.home) // 类型安全的属性访问
console.log(lang.format.date) // 编译时类型检查

函数和组件支持

import MyComponent from './MyComponent.vue'

const lang = createLang({
  chs: {
    // 支持函数
    greet: (name: string) => `你好,${name}!`,
    formatPrice: (price: number) => `¥${price.toFixed(2)}`,
    // 支持 Vue 组件
    headerComponent: <MyComponent theme="dark" />,
    footerComponent: <MyComponent theme="light" />,
  },
  en: {
    greet: (name: string) => `Hello, ${name}!`,
    formatPrice: (price: number) => `$${price.toFixed(2)}`,
    headerComponent: <MyComponent theme="dark" />,
    footerComponent: <MyComponent theme="light" />,
  },
})

// 使用函数
console.log(lang.greet('Vue')) // "你好,Vue!"
console.log(lang.formatPrice(99.99)) // "¥99.99"

// 在模板中使用组件
// <component :is="lang.headerComponent" />

临时语言切换(不持久化)

// 临时切换语言,不保存到 localStorage
lang.$.set('en', false)

// 刷新页面后会恢复之前保存的语言

自定义存储配置

const lang = createLang(langData, {
  storageKey: 'my-app-language', // 自定义存储键
  default: 'chs', // 默认语言
})

🌟 最佳实践

1. 分离语言文件并保证类型安全

// lang/chs.ts
export const chs = {
  common: {
    save: '保存',
    cancel: '取消',
    confirm: '确认',
    loading: '加载中...',
  },
  nav: {
    home: '首页',
    about: '关于',
    contact: '联系我们',
  },
  pages: {
    home: {
      title: '欢迎使用 vue-localeflow',
      subtitle: '轻量级 Vue 3 国际化解决方案',
    },
  },
} as const

export type ILang = typeof chs
// lang/en.ts
import type { ILang } from './chs'

export const en: ILang = {
  common: {
    save: 'Save',
    cancel: 'Cancel',
    confirm: 'Confirm',
    loading: 'Loading...',
  },
  nav: {
    home: 'Home',
    about: 'About',
    contact: 'Contact Us',
  },
  pages: {
    home: {
      title: 'Welcome to vue-localeflow',
      subtitle: 'Lightweight Vue 3 i18n Solution',
    },
  },
}
// lang/index.ts
import { createLang } from 'vue-localeflow'
import { chs } from './chs'
import { en } from './en'

export const lang = createLang(
  { chs, en },
  {
    default: 'chs',
    storageKey: 'app-language',
  }
)

// 导出类型以供其他地方使用
export type { ILang } from './chs'

2. 任意地方使用

由于 lang 对象是响应式的,您可以在项目的任意地方直接导入和使用,无需额外的 Hook 或 Provider。

  • 组件外使用
import { lang } from '@/lang'

export async function fetchUserData() {
  const response = await fetch('/api/user', {
    headers: {
      'Accept-Language': lang.$.lang === 'chs' ? 'zh-CN' : 'en-US',
    },
  })

  if (!response.ok) {
    throw new Error(lang.message.error) // 直接使用当前语言的错误信息
  }

  return response.json()
}
  • 组件内使用
<template>
  <div>{{ lang.greeting }}</div>
</template>