Skip to content

Example project integration

Sam A. Horvath-Hunt edited this page Oct 10, 2022 · 4 revisions

intlc deliberately takes a non-monolithic approach to the compilation of translation messages. We intend to improve ease of use and integration (#160), however for the time being you'll need to do a little bit of extra bootstrapping yourself.

Compile script

You'll need a shell script or similar which can find all the translation files in your project and feed them into intlc. For this reason we recommend a consistent, distinct approach to file naming, such as lang/<locale>.translations.json.

This shell script is very similar to what we use at Unsplash on the Web team. It compiles all our translations across all locales to sibling files; for example ja-JP.translations.json will be compiled to ja-JP.tsx. Everything in our repo compiles in around 200ms.

#!/usr/bin/env bash

dirs=$(fd -t d lang)

compile_dir() {
  dir="$1"
  files=$(find "$dir" -name "*.translations.json" -type f)

  if [ -n "$files" ]; then
    for file in $files; do
      filename=$(basename "$file")
      locale="${filename%%.*}"

      intlc compile "$file" -l "$locale" > "$dir/$locale.tsx"
    done

    cp ./templates/lang-index.ts "$dir/index.ts"
  fi

}

# Extracted into a function so that we can fork for each directory, improving performance.
for dir in $dirs; do compile_dir "$dir" & done

wait

(The use of fd over find at the top is optional.)

Index

In the cp above we copy an index to every lang directory. This is what you'll import from your code. This file needs to re-export from each compiled locale. It will very roughly look something like this:

import * as enUS from './en-US'
import * as jaJP from './ja-JP'

export type Translations = typeof enUS

export const getTranslations = (loc: 'en-US' | 'ja-JP'): Translations => {
  switch (loc) {
    case 'en-US': return enUS
    case 'ja-JP': return jaJP
  }
}

Type safety

The index is where type safety can be enforced, as with the use of Translations on the return type above. Your master translations, for example English, can be used to ensure compatible type signatures across locales.

In this way type safety across locales isn't a concern of intlc and is instead offloaded to tsc. TypeScript's subtyping makes this particularly straightforward, as messages needn't necessarily use the same interpolations across locales, they need merely be compatible i.e. { name: string } and { age: number } are compatible insofar as they can be intersected, but { name: string } and { name: number } are not because you can't provide a string & number.

Code splitting

This is something we're working on now with React suspense and SSR in mind. We'll update this page when we've got something we're ready to share.

In theory, because you're just working with output .ts files, this can already be implemented in any way you'd please, for example making the above imports dynamic and returning a promise.

Watching

You can integrate watching in any number of ways. We currently use watchexec:

watchexec -f '*.translations.json' -n -- sh -c './compile.sh && echo OK'
Clone this wiki locally