{"id":20466914,"url":"https://github.com/fwh1990/i18n-chain","last_synced_at":"2025-04-13T09:11:42.286Z","repository":{"id":51541211,"uuid":"230229609","full_name":"fwh1990/i18n-chain","owner":"fwh1990","description":"High performance i18n with typescript that support React, React-Native, Taro and NodeJs","archived":false,"fork":false,"pushed_at":"2021-05-11T10:04:21.000Z","size":952,"stargazers_count":34,"open_issues_count":12,"forks_count":4,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-04-12T14:13:45.956Z","etag":null,"topics":["i18n","i18n-typescript","react-i18n","react-native-i18n","typescript-i18n"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fwh1990.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-26T08:51:52.000Z","updated_at":"2025-01-01T10:21:10.000Z","dependencies_parsed_at":"2022-09-06T20:50:54.531Z","dependency_job_id":null,"html_url":"https://github.com/fwh1990/i18n-chain","commit_stats":null,"previous_names":["fwh1990/react-i18n-chain"],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fwh1990%2Fi18n-chain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fwh1990%2Fi18n-chain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fwh1990%2Fi18n-chain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fwh1990%2Fi18n-chain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fwh1990","download_url":"https://codeload.github.com/fwh1990/i18n-chain/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248658330,"owners_count":21140925,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["i18n","i18n-typescript","react-i18n","react-native-i18n","typescript-i18n"],"created_at":"2024-11-15T13:26:22.810Z","updated_at":"2025-04-13T09:11:42.267Z","avatar_url":"https://github.com/fwh1990.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"说到国际化，你是否也常年奔波于复制粘贴的重复劳动里？像 `t('home:submit')` `t('common:something:success')` 这些没有任何提示，需要脑子去记，不仅开发效率低，而且键盘敲快一点就容易打错字母，重点是你基本发现不了这种错误。\n\n我更喜欢有提示的代码，利用`typescript`，我发明了一种使用链式操作的i18n组件，并拥有所有提示，就类似 `i18n.common.something.success` 这种，代码可以自动补全，保证不会写错。\n\n[![License](https://img.shields.io/github/license/fwh1990/i18n-chain)](https://github.com/fwh1990/i18n-chain/blob/master/LICENSE)\n[![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/fwh1990/i18n-chain/CI/master)](https://github.com/fwh1990/i18n-chain/actions)\n[![Codecov](https://img.shields.io/codecov/c/github/fwh1990/i18n-chain)](https://codecov.io/gh/fwh1990/i18n-chain)\n\n\n# 兼容性\n| IE | Edge | Chrome | Firefox | Safari | Node |\n| -- | -- | -- | -- | -- | -- |\n| 9+ | 12+ | 5+ | 4+ | 5+ | * |\n\n# 安装\n### React | RN | Taro@3\n```bash\nyarn add @i18n-chain/react\n```\n\n### NodeJS\n```bash\nyarn add @i18n-chain/node\n```\n\n# 使用\n\n### 定义本地化文件\n```typescript\n// ./src/i18n/locales/en.ts\n\nconst en = {\n  button: {\n    submit: 'Submit',\n    cancel: 'Go back',\n  },\n  user: {\n    profile: 'Tom',\n  },\n};\n\nexport default en;\nexport type Locale = typeof en;\n```\n\n```typescript\n// ./src/i18n/locales/zh.ts\n\nimport { Locale } from './en';\n\nconst zh: Locale = {\n  button: {\n    submit: '提交',\n    cancel: '返回',\n  },\n  user: {\n    profile: '原罪',\n  },\n};\n\nexport default zh;\n```\n\n### 创建i18n实例\n```typescript\n// ./src/i18n/index.ts\n\nimport { createI18n } from '@i18n-chain/*';\nimport en from './locales/en';\n\nconst i18n = createI18n({\n  defaultLocale: {\n    key: 'en',\n    values: en,\n  },\n});\n\nexport default i18n;\n```\n\n### 导入语言\n第一种, **直接定义**：\n```typescript\nimport { createI18n } from '@i18n-chain/*';\nimport zh from './locales/zh';\n\nconst i18n = createI18n({\n  defaultLocale: { ... },\n});\n\ni18n.define('zh', zh);\n\nexport default i18n;\n```\n\n第二种, **异步导入**。当组件检测到语言未定义时，会自动触发`loader`函数\n```typescript\nconst i18n = createI18n({\n  defaultLanguage: { ... },\n  loader: (name) =\u003e import('./locales/' + name),\n});\n\nexport default i18n;\n```\n\n### 切换语言\n```typescript\ni18n.locale('zh');\n```\n\n### 字符串模板\n有时候您需要在组件外预定义一系列内容，此时不得不使用字符串模板（`'button.submit'`）来代表，并在组件渲染时翻译成相应的文字。很显然，这串字符串没有任何提示，即使写错了也没人知道。\n\n别担心，框架提供了生成字符串模板的功能，现在一起试试\n```typescript\nconst key = i18n.literal.button.submit;\nkey === 'button.submit' // true\n\nconst value = i18n.translate(key);\nvalue === 'Submit' // true\n```\n酷，带有提示的字符串模板也重新拥有了灵魂，不必再担心会写错了，让IDE和TS去处理吧。\n\n### 带参数的模板\n当你想用参数的时候，你需要把模板写成数组的形式\n```javascript\nconst en = {\n  property: ['{{property1}}template{{property2}}', { property1: value2, property2: value2 }],\n};\n```\n数组第二个元素就是参数列表以及，你可以设置参数的默认值。\n\n```typescript\nconst en = {\n  user: {\n    profile: [\n      'My name is {{name}}, I born in {{country}}, I am {{age}} old now, my birthday is {{birthday}}',\n      {\n        country: undefined,\n        name: 'Tom',\n        age: (value: number = 20) =\u003e {\n          if (value \u003c= 1) {\n            return `${value} year`;\n          } else {\n            return `${value} years`;\n          }\n        },\n        birthday: (value: Date) =\u003e {\n          return value.toString();\n        },\n      },\n    ],\n  },\n};\n\n////////////////////////////////////\n// 上面的代码可以自动推导出和下面一致的类型：\ninterface User {\n  Profile {\n    country: string | number;\n    name?: string;\n    age?: number;\n    birthday: Date;\n  }\n}\n/////////////////////////////////////\n\n// 最小化调用\ni18n.chain.user.profile({\n  country: 'Earth',\n  birthday: new Date(),\n});\n\n// 增加可选的属性：`name` 和 `age`\ni18n.chain.user.profile({\n  country: 'Earth',\n  name: 'Lucy',\n  age: 30,\n  birthday: new Date(),\n});\n```\n\n方法参数 `age` 和 `birthday` 的区别是，`age`的形参中含有默认值`(value: number = 20) =\u003e {...}`，而后者没有。有默认值意味着调用的时候可以不传参数。\n\n------------\n\n普通参数如果没有默认值，需要设置成`undefined`，这样typescript才能正确识别，并强制要求调用者输入对应的参数值。\n\n```typescript\nconst en = {\n  template: ['Hello, {{world}}', { world: undefined }]\n};\n```\n\n### 在Hooks中使用\n\n```typescript jsx\nimport React, { FC } from 'react';\nimport i18n from '../i18n';\n\nconst App: FC = () =\u003e {\n  // 使用use使得切换语言时可以重渲染\n  const chain = i18n.use();\n\n  return \u003cbutton\u003e{chain.button.submit}\u003c/button\u003e;\n};\n\nexport default App;\n```\n\n### 在Class组件中使用\n\n```typescript jsx\nimport React, { PureComponent } from 'react';\nimport { InjectedI18nProps } from '@i18n-chain/react';\nimport i18n from '../i18n';\n\ntype Props = InjectedI18nProps\u003ctypeof i18n\u003e;\n\nclass App extends PureComponent\u003cProps\u003e {\n  render() {\n    const { chain } = this.props;\n\n    return \u003cbutton\u003e{chain.button.submit}\u003c/button\u003e;\n  }\n};\n\n// 使用高阶组件使得切换语言时可以重渲染\nexport default i18n.hoc(App);\n```\n\n# 在线Demo\n[CodeSandbox](https://codesandbox.io/s/sleepy-dream-s7uqh)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffwh1990%2Fi18n-chain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffwh1990%2Fi18n-chain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffwh1990%2Fi18n-chain/lists"}