Skip to content

快速开始

环境要求

  • Node.js 22+

安装依赖

我这里用的是 yarn,当然你可以自选其他包管理器也行,比如 npm 。

bash
yarn add magic-i18next -D

在你项目的根目录新建一个 magic-i18next.config.ts文件

项目核心配置都在 magic-i18next.config.ts

注意: 这里涉及私钥等一些私密信息,建议把它添加到 .gitignore 中,不要直接提交到版本控制仓库。

通用配置

ts
interface MagicI18nextConfig {
  /**
   * 扫描的入口目录
   * @default './src'
   */
  scanDir: string;

  /**
   * 要扫描的文件扩展名
   * @default ['.vue', '.ts', '.tsx', '.js', '.jsx']
   */
  extensions: string[];

  /**
   * 国际化文件的输出目录
   * @default './src/locales'
   */
  outputDir: string;

  /**
   * 默认语言
   * @default 'en'
   */
  defaultLanguage: string;

  /**
   * 排除的目录或文件
   * @default ['node_modules', 'dist', 'build']
   */
  exclude: string[];

  /**
   * 参数格式模板,{index} 会被替换为参数索引
   * @default '{index}' // vue-i18n, next-i18n 等
   * @example '{{index}}' // react-i18next
   */
  paramFormat: string;

  /**
   * 国际化文件的默认目录(用于 json2Excel)
   * @default './src/locales'
   */
  defaultLocalesDir: string;

  /**
   * 生成的 Excel 文件的默认路径(用于 json2Excel)
   * @default './data.xlsx'
   */
  defaultOutputExcelPath: string;

  /**
   * 飞书多维表格同步配置(用于 push)
   */
  feishuConfig: {
    /** 飞书应用 App ID */
    appId: string;
    /** 飞书应用 App Secret */
    appSecret: string;
    /** 多维表格的 app_token(从表格 URL 或知识库节点获取) */
    appToken: string;
    /** 多维表格数据表 ID(table_id) */
    tableId: string;
    /** 本地语言 JSON 目录,不填则使用 outputDir */
    localeDir?: string;
    /** 存 key 的列名,若有「文本」列会改为此名,否则新建此列 @default 'key' */
    keyFieldName?: string;
    /** 飞书建表时可能自带的第一列名,若存在则改名为 keyFieldName @default '文本' */
    defaultFirstColumnName?: string;
    /** 状态列名(单选:待处理/已处理)@default '状态' */
    statusFieldName?: string;
    /** 语言代码 -> 飞书列名,如 { cn: '中文', en: 'English' },未列出的用语言代码本身 */
    fieldMap?: Record<string, string>;
  };

  /**
   * DeepSeek 翻译(yarn translate)
   * 环境变量 DEEPSEEK_API_KEY 可覆盖 apiKey
   */
  deepSeek: {
    apiKey: string;
    model: string;
    batchSize: number;
    retries: number;
    retryDelayMs: number;
    /** 语言代码 -> 英文语言名(用于翻译 prompt) */
    localLabel: Record<string, string>;
  };

  /**
   * Google Sheets 同步配置(用于 push-google)
   */
  googleSheetsConfig: {
    /** 表格 ID(URL 中 /d/<id>/ 那段) */
    spreadsheetId: string;
    /** Service Account 凭证文件路径(相对项目根目录) */
    credsPath: string;
    /** 本地语言 JSON 目录,不填则使用 outputDir */
    localeDir?: string;
    /** 写入第几个 sheet(从 0 开始)@default 0 */
    sheetIndex?: number;
    /** 代理配置(国内建议开启) */
    proxy?: {
      /** http 或 socks5 */
      protocol: 'http' | 'socks5';
      /** 例如 127.0.0.1 */
      host: string;
      /** 例如 10808 */
      port: number;
    };
  };
}

完整配置

ts
const config: MagicI18nextConfig = {
  scanDir: './src',
  extensions: ['.vue', '.ts', '.tsx', '.js', '.jsx'],
  outputDir: './src/locales',
  defaultLanguage: 'cn',
  exclude: ['node_modules', 'dist', 'build'],
  paramFormat: '{index}', // 默认格式,适用于 vue-i18n, next-i18n 等
  defaultLocalesDir: './src/locales',
  defaultOutputExcelPath: './data.xlsx',
  feishuConfig: {
    appId: '',
    appSecret: '',
    appToken: '',
    tableId: '',
    localeDir: './src/locales',
    keyFieldName: 'key',
    defaultFirstColumnName: '文本',
    statusFieldName: '状态',
    fieldMap: { cn: '中文', en: 'English', jp: 'Japanese' },
  },
  googleSheetsConfig: {
    spreadsheetId: '',
    credsPath: './src/google-sheets/google-creds.json',
    sheetIndex: 0,
    localeDir: './src/locales',
    // 中国大陆可能需要配置一下代理,不然可能没法访问,按你具体的配置走代理
    proxy: { protocol: 'http', host: '127.0.0.1', port: 10808 },
  },
  deepSeek: {
    apiKey: '',
    model: '',
    batchSize: 40,
    retries: 2,
    retryDelayMs: 1500,
    localLabel: {
    // key是你json的文件名,value是对应具体的语言,比如这里的 en, 则对应 en.json
      en: 'English',
      jp: 'Japanese',
      ko: 'Korean',
      fr: 'French',
      de: 'German',
      es: 'Spanish',
      pt: 'Portuguese',
      ru: 'Russian',
      ar: 'Arabic',
      vi: 'Vietnamese',
      th: 'Thai',
      cn: 'Simplified Chinese',
      tw: 'Traditional Chinese',
      hk: 'Traditional Chinese (Hong Kong)',
    },
  },
};

export default config;

配置多语言的json文件

src/locales目录下新建一个文件夹比如en, 然后在en文件夹下新建一个文件en.json

使用

当你安装并配置好之后,可以使用:

这里以Vue3为例:

使用$k标记:($k的封装请跳转到: Vue3中使用$k)

tsx
// Vue的模板写法:
<div>{{ $k('普通文本') }}</div>
// 带参数
<div>{{ $k(`带有参数${param1}, 参数${param2}`) }}</div>

自动抽离key

bash
npx magic

此时,将会自动识别标记了$k(``)的文案,并自动填入到对应的xxx.json中。

经过抽离之后标记处则会变成$k的标签模板字符串 (Tagged Template Literals):

tsx
// 类似styled-component的写法(没有小括号)
<div>{{ $k`auto.1__普通文本` }}</div>

即使是带有参数的情况,也很直观

tsx
<div>{{ $k`auto.2__带有参数${param1}, 参数${param2}` }}</div>

注意

这里的前缀是对应的json中的key,请不要手动修改 标签模板字符串 这里的内容。

如果有改动的话,请加上小括号改回 $k('修改的新文本')

这样,你就可以只当做单一语言开发了。

只扫描单一文件

如果你遇到一些特殊情况,只想扫描单一个文件,可以使用:

npx magic ./src/xxx.vue

忽略下一行的扫描

使用 i18n-ignore 注释的形式即可忽略下一行

tsx
/* i18n-ignore */
const word = $k('忽略扫描替换的文本');

在React中的用法也同理

tsx
// React的 tsx 写法:
<div>{ $k('普通文本') }</div>
// 带参数
<div>{ $k(`带有参数${param1}, 参数${param2}`) }</div>

可能有的同学会问 为什么要加 auto这个前缀,其实主要是区别一个情况是: 中文相同,英文不同,这样就可以新建一个别的key,比如extra, 因为扫出来的都是带有auto前缀的。

json
{
  "auto": {
    "1": "此语言相同,别的语言不同"
  },
  "extra": {
    "1": "此语言相同,别的语言不同"
  }
}

上传到飞书

如果你们对文本有产品要求的话,或者有专职翻译的同学的话,中国大陆的同学可以考虑将这些json上传到飞书的多维表格,

可以先参考上传到飞书的配置

然后要先配置好 magic-i18next.config.ts 对应feishuConfig选项

执行命令:

bash
npx magic push:feishu

待他们在飞书上翻译好之后,你再使用命令:

bash
npx magic pull:feishu

这样就会强制更新你本地的json文件。

上传到google sheets

可以先参考上传到google sheets的配置

同样也要先配置好 magic-i18next.config.ts 对应googleSheetsConfig

执行命令:

bash
npx magic push:google

待他们在google sheets上翻译好之后,你再使用命令:

bash
npx magic pull:google

注意,无论是 push 还是 pull 都是强制更新的,自己注意利用好git,防止代码丢失

转成本地的excel文件

如果你不想上传到云端,也可以转成 excel 交给翻译的同学,输入输出路径根据 magic-i18next.config.ts 中的 defaultOutputExcelPath 和 defaultLocalesDir 决定,

执行命令:

bash
npx magic json2Excel

待他们在excel上翻译好之后,你再使用命令:

bash
npx magic excel2Json

注意也都是强制更新文件的


接入DeepSeek

如果你这个项目没有专门的翻译岗帮你的话,可以考虑一下接入DeepSeek帮你,10块钱就可以帮你翻译很多很多文案 玩很久了

同样也要先配置好 magic-i18next.config.ts 对应deepSeek配置

执行命令:

bash
npx magic deepSeek

说明:

  • 会提示输入语言(30 秒超时后使用 defaultLanguage
  • 会生成/更新 outputDir/<lang>.json

其它

安装时候忘记了指令可以使用 --help 或者 -h 查看

npx magic -h