プレーン Typescript でこのブログのバイリンガル機能を作成する方法

皆さん、2022 年明けましておめでとうございます!今日は、ほとんどのブログ投稿とは異なること、つまり、バイリンガル ブログを純粋な Typescript で実装する方法についてお話したいと思います。

2015 年にこのブログを作成して以来、より多くの読者にリーチするためにバイリンガルにしたいと常に考えていましたが、2019 年末にようやく実装しました。 i18next などのサードパーティ ライブラリ。また、実装の型システムにおける Typescript の優れた機能に大きく依存しています。

私のソリューションは、おそらくプロの基準で最も「適切」またはスケーラブルではありませんが、個人のブログの特定のユースケースにうまく適合すると思います.いくつかの重要な利点があります:

  • 型システムは、エントリの変換を忘れないことを保証します
  • 言語ごとに任意に異なる Javascript を使用できるため、非常に柔軟です (この Web サイトは React で実装されているため、任意の JSX 1 を使用できます) )。これは、選択した言語で特定の UI 要素のみをレンダリングしたい場合に便利なプロパティです (たとえば、中国では Twitter が禁止されているため、このサイトの中国語版から Twitter リンクを削除しました)。
  • ブログのためだけに i18n ライブラリを学ぶ必要はありません

したがって、多言語の個人 Web サイトを作成する場合は、同様のアプローチを使用することをお勧めします。

このブログでは、静的サイト ジェネレーター GatsbyJS を使用しています。静的サイト ジェネレーターに慣れていない場合は、"テンプレート" を使用して、Markdown などの形式のコンテンツを適切な HTML ページに変換することができます。 2

ブログ投稿用に、言語ごとに個別のマークダウン ファイルを用意しています。たとえば、この投稿の中国語版と、現在お読みになっているテキストは、別のマークダウン ファイルに保存されています。ただし、「テンプレート」にはまだ多くのテキストが含まれています。例としては、右側のサイドバーにある私の略歴、さまざまなメニュー項目、ブログ投稿タグなどがあります。

GatsbyJS の「テンプレート」は、特定の React コンポーネントである Javascript (そして、私は JS にトランスパイルする Typescript を使用することにしました) です。これらの React コンポーネントと翻訳は静的 HTML に組み込まれます。 一方、Python を使用して静的サイト ジェネレーターを使用するとします。その場合、理想的には、Web サイトの翻訳を動的にロードするオーバーヘッドを回避するために、ビルド時に翻訳を実行できるように、Python で国際化を実装する必要があります。

私の国際化の実装のほとんどは、translation.tsx ファイルにあります:

まず、en があります すべての翻訳エントリを英語で保存するオブジェクト:

const en = {
  ai: "AI",
  algorithms: "Algorithms",
  archive: "Archive",
  ...
};

en以降 は単なるオブジェクトですが、jsx オブジェクトや関数などのよりエキサイティングなデータをエントリとして保存することもできます:

  all_n_posts: (n: number) => (
    <>
      All <Link to={`/en/archive`}>{n} posts</Link>
    </>
  ),

en で 定義されたオブジェクトとして、typeof によってその型を照会できます オペレーター:

export type Translations = typeof en;

このリフレクション機能は便利ですが、ほとんどのプログラミング言語にはありません。具体的には、型を自分で定義する手間を省きます。これは、言語機能が DRY 原則の達成にどのように役立つかを示す好例です。

今度は Translationsen の構造を反映した別のオブジェクトを作成できます オブジェクトですが、明示的な型要件があります:

const zh: Translations = {
  ai: "AI",
  algorithms: "算法",
  archive: "博文目录",
  ...
};

このように、型システムにより、エントリの変換を忘れることはありません。

そして、すべての言語の翻訳を 1 つのオブジェクトにまとめることができます。このオブジェクトは、特定の翻訳エントリを照会するためのテンプレートのメイン エントリ ポイントとして機能します:

export const translations = {
  en: en,
  zh: zh,
};

次に keyof を使用します 翻訳のキーの共用体型を取得する演算子:この場合、 "en" | "zh" .keyof Typescript のもう 1 つの優れたリフレクション機能です。ただし、オブジェクトではなく型を想定しているため、別の typeof を適用する必要があります。 keyof を適用する前の演算子 :

export type Language = keyof typeof translations;

たとえば、現在の言語をパラメーターとして渡す場合など、言語の明示的な型注釈が必要な場合は常に、上記の共用体型を使用します。

最後に Object.keys を使用します 言語のリストを取得して、すべての言語をループできるようにします。

export const languages = Object.keys(translations) as Language[];

この Web サイトはバイリンガルのみであり、他の言語での記述方法はわかりません。それでも、英語を「デフォルト」言語として扱うことを除いて、実装に特定の言語のハードコーディングはありません。したがって、それは些細なことです。この実装を拡張して、より多くの言語をサポートします。必要なのは、Translations で別のオブジェクトを定義することだけです。 入力して translations のエントリとして追加します .

翻訳を使用するには、まずページの現在の言語をそのコンポーネントに渡す必要があります。次に、translations[lang]["entry"] を使用できます。 正確に翻訳が必要な場所 ("entry" を置き換えます) translations[lang]["all_n_posts"](n) のように関数を呼び出すだけなので、このスキームは関数に対しても機能します。 .

それでおしまい!国際化ロジック全体を実装しました!新しいエントリを追加するには、en に翻訳を追加するだけです。 そして zh ただし、バイリンガル ブログを維持する上で最も困難な部分は、常に実際のブログ投稿を翻訳することです。また、このサイトの多数の英語のみのバージョンの投稿が示すように、完璧な仕事をしたとは言えません。 、私はそれに取り組み続けるつもりです。私のアプローチの技術的な側面が、あなたにも試してみるように促すことを願っています!

<オール>
  • JSX に慣れていない人のために説明すると、JSX は Javascript の構文拡張であり、HTML のような UI コードを簡単に記述できるようになります。 React.js と連携するように設計されていますが、Vue.js などの他のテクノロジと併用することもできます。 JSXの紹介です↩
  • GatsbyJS の特定のケースでは、実際の状況はより複雑ですが、詳細については Web サイトにアクセスしてください。↩