Back

gt-next@6.8.0

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

Overview

We often find that the more mature a codebase becomes, the more fragmented its content is. Sentences end up scattered across functions, utilities, logic, and services.

function getSubject(gender) { 
  return gender === "male" ? "boy" : "girl" 
}
function getObject(toy, gender) { 
  return toy === "ball" ? "ball" : getSubject(gender)
}

function Component({ gender, toy }) {
  return (
    <>
      <p>
        The beautiful {getSubject(gender)} plays with the {getObject(toy, gender)}.
      </p>
    </>
  )
}

When it inevitably comes time to internationalise, developers find that they’ve painted themselves into a corner. Enforcing things like agreement, conjugation, and changes to word order across multiple files isn’t manageable without a major refactor. Traditionally, this meant manually extracting every possible permutation of each sentence and adding them to a translation dictionary.

In gt-next 6.8.0, we’re doubling down on the belief that a strong i18n library should adapt to a codebase, rather than the other way around. While gt-next already translates content inline, it lacks two fundamental features of such a library: (1) support for sentence fragmentation and (2) reusable content, while also preserving word agreement, conjugation, or word order changes.

We’re introducing the <Static> component to allow static function calls directly inside translations.

function getSubject(gender) { 
  return gender === "male" ? "boy" : "girl" 
}
function getObject(type, gender) { 
  return type === "ball" ? "ball" : getSubject(gender)
}

function Component({ gender, toy }) {
  return (
    <T>
      <p>
        The beautiful <Static>{getSubject(gender)}</Static> plays with the <Static>{getObject(toy, gender)}</Static>.
      </p>
    </T>
  )
}

Important Considerations

That said, we strongly emphasise using the <Static> component carefully and judiciously. The <Static> component, while powerful, can also lead to major increases in the number of translation entries. If used incorrectly, this could have negative effects on application load times.

How to use <Static>

Just like the <T> and <Var> components, the <Static> component is a flag that tells the CLI tool where and where not to look for translatable content. It tells the CLI tool to dereference a function call inside the <Static> tags and catalogue all possible content returned by that function. Treat every return statement as if it had a <T> component wrapping it.

Once the CLI tool has found all possible outputs from a function call, it creates a separate translation entry for each possible output. For example, the following code creates two separate translation entries: "The boy is beautiful" and "The girl is beautiful". Because a different translation entry exists for each possible output, we can support agreement, conjugation, and word order in a fragmented sentence: "El niño es hermoso" and "La niña es hermosa".

function getSubject(gender) { 
  return gender === "male" ? "boy" : "girl" 
}
function Component({ gender }) {
  return (
    <T>
      The <Static>{getSubject(gender)}</Static> is beautiful.
    </T>
  )
}

Limitations and Future Improvements

Multiplication

As mentioned earlier, the <Static> component, if used too liberally, can generate a large number of translation entries which could have a negative impact on load-time performance. For example, consider a component with two <Static> components, each wrapping a function call with two possible outcomes. In this case, four translation entries are created. Every additional <Static> component multiplies the number of translations by the number of possible outcomes from each function call.

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> plays with the <Static>{getObject(toy)}</Static>.
    </T>
  )
}

Syntax

You should treat every return statement as if it had a <T> component wrapping it. Any variables or function calls that are dynamic must still be wrapped in <Var> components.

Currently, <Static> only supports function calls as children, but in future it will be able to support more complex expressions. As of gt-next 6.8.0, the following syntax is supported for static functions:

function getExamples(key) {
  switch (key) {
    case "string, number, and boolean literals":
      if (condition1) {
        return "The boy"
      } else if (condition2) {
        return 22
      } else {
        return true
      }
    case "jsx expressions":
      return (
        <>
          Hello, <Static>{getTitle(title)}</Static>. How are you, <Var>{name}</Var>?
        </>
      );
    case "ternary operators":
      return condition ? "The boy" : "The girl"      
    case "function calls":
      return otherStaticFunction();
  }
}

Conclusion

gt-next 6.8.0 introduces the <Static> component as a solution to sentence fragmentation without compromising translation coverage or correct grammatical agreement.