返回

gt-next@6.8.0

Ernest McCarter avatarErnest McCarter
gt-reactgt-nextgtx-cliv6.8.0statictranslationi18n

概览

我们经常发现,代码库越成熟,内容就越分散。 同一句话会被拆成几段,散落在 functionsutilities、业务逻辑和 services 等各个部分。

function getSubject(gender) { 
  return gender === "male" ? "男孩" : "女孩" 
}
function getObject(toy, gender) { 
  return toy === "球" ? "球" : getSubject(gender)
}

function Component({ gender, toy }) {
  return (
    <>
      <p>
        漂亮的{getSubject(gender)}正在玩{getObject(toy, gender)}。
      </p>
    </>
  )
}

当应用最终不可避免地走到需要做国际化这一步时,开发者往往会发现自己已经把路走“死”了。 如果不进行大规模重构,就很难在多个文件之间统一处理数的一致、动词变位以及语序变化等问题。 传统做法是,手动提取每个句子的所有可能变体,并将它们逐一添加到翻译字典中。

gt-next 6.8.0 中,我们进一步坚定了这样一个理念:一个强大的 i18n 库应该适配现有代码库,而不是反过来。 虽然 gt-next 已经支持内联翻译内容,但它仍然缺少这类库的两个基础特性: (1) 支持句子拆分,以及 (2) 在保持数的一致、动词变位或语序变化等语言特性不丢失的前提下实现内容复用。

我们引入了 <Static> 组件,使你可以在翻译内部直接调用静态函数。

function getSubject(gender) { 
  return gender === "male" ? "男孩" : "女孩" 
}
function getObject(type, gender) { 
  return type === "球" ? "球" : getSubject(gender)
}

function Component({ gender, toy }) {
  return (
    <T>
      <p>
        漂亮的<Static>{getSubject(gender)}</Static>正在玩<Static>{getObject(toy, gender)}</Static>。
      </p>
    </T>
  )
}

重要注意事项

尽管如此,我们仍强烈建议谨慎、合理地使用 <Static> 组件。 <Static> 组件虽然功能强大,但也可能导致翻译条目数量大幅增加。 如果使用不当,这可能会对应用程序的加载时间产生负面影响。

如何使用 <Static>

<T><Var> 组件类似,<Static> 组件是一个标记,用来告诉 CLI 工具哪些地方应该、哪些地方不应该查找可翻译内容。 它会指示 CLI 工具对 <Static> 标签内的函数调用进行解引用,并将该函数可能返回的所有内容都收集进翻译目录。 把每一个 return 语句都当作是被 <T> 组件包裹了一样来处理。

当 CLI 工具找到某个函数调用的所有可能输出后,它会为每一种可能的输出创建一个单独的翻译条目。 例如,下面的代码会创建两个不同的翻译条目:"The boy is beautiful" 和 "The girl is beautiful"。 由于每种可能的输出都有单独的翻译条目,我们就可以在一个被拆分的句子中支持性数配合、动词变位和词序,比如:"El niño es hermoso" 和 "La niña es hermosa"。

function getSubject(gender) { 
  return gender === "male" ? "boy" : "girl" 
}
function Component({ gender }) {
  return (
    <T>
      这个<Static>{getSubject(gender)}</Static>很漂亮。
    </T>
  )
}

限制与未来改进方向

乘法效应

如前所述,如果过于频繁地使用 <Static> 组件,可能会生成大量翻译条目,从而对加载时间产生负面性能影响。 例如,设想一个组件中包含两个 <Static> 组件,每个都包裹一次具有两种可能结果的函数调用。 在这种情况下,会创建四个翻译条目。 每增加一个 <Static> 组件,翻译条目的数量就会再乘以每次函数调用的可能结果数量。

function getSubject(gender) { 
  return gender === "male" ? "boy" : "girl" 
}
function getObject(toy) { 
  return toy === "ball" ? "ball" : "crayon"
}
function Component({ gender, toy }) {
  return (
    <T>
      <Static>{getSubject(gender)}</Static> 玩 <Static>{getObject(toy)}</Static>。
    </T>
  )
}

语法

需要注意的是,应将每一个 return 语句都视为被一个 <T> 组件包裹。 任何动态的变量或函数调用也必须包裹在 <Var> 组件中。

目前,<Static> 只支持将函数调用作为子元素,但未来会支持更复杂的表达式。 从 gt-next 6.8.0 起,静态函数支持以下语法:

function getExamples(key) {
  switch (key) {
    case "string, number, and boolean literals":
      if (condition1) {
        return "男孩"
      } else if (condition2) {
        return 22
      } else {
        return true
      }
    case "jsx expressions":
      return (
        <>
          你好,<Static>{getTitle(title)}</Static>。<Var>{name}</Var>,你好吗?
        </>
      );
    case "ternary operators":
      return condition ? "男孩" : "女孩"      
    case "function calls":
      return otherStaticFunction();
  }
}

结论

gt-next 6.8.0 引入了 <Static> 组件,在不牺牲翻译覆盖范围或正确语法一致性的前提下,为解决句子碎片化问题提供了方案。