1
/
5

hi18n (i18nライブラリ) の使い方

hi18nとは

hi18n は現在Wantedlyで開発中の、TypeScript/JavaScript向け翻訳テキスト管理ライブラリ (i18nライブラリの一種) です。

GitHub - wantedly/hi18n: message internationalization meets immutability and type-safety
Installation: npm install @hi18n/core @hi18n/react-context @hi18n/react npm install -D @hi18n/cli # Or: yarn add @hi18n/core @hi18n/react-context @hi18n/react yarn add -D @hi18n/cli Put the following file named like src/locale/index.ts: And you can use th
https://github.com/wantedly/hi18n

開発の動機や設計思想、詳しい特徴などは別の記事で紹介していますが、大まかには以下の特徴があります。

  • 翻訳IDや翻訳の引数に正しく型がつく。
  • Reactのような宣言的な設計との相性がよい。
  • JavaScriptの既存の開発環境 (Webpackなど) に自然に統合される。
    • たとえば、hi18nのために特別な設定をしなくても、ホットリロードが使えるようになる。
    • 翻訳データの分割ロードが必要な場合も、モジュールバンドラーの機能を使って行う。

本稿では実際に使いたい・試したい人のための情報として、導入手順と使い方を紹介します。

導入とセットアップ

ここではReact + TypeScript環境を想定した手順を紹介します。まず必要なパッケージを入れます。

npm install @hi18n/core @hi18n/react-context @hi18n/react
npm install -D @hi18n/cli

# または:
yarn add @hi18n/core @hi18n/react-context @hi18n/react
yarn add -D @hi18n/cli

次に翻訳ファイルを用意します。1ファイル構成も可能ですが、ここでは複数ファイル構成で紹介します。

// src/locale/index.ts
// (他の名前でもOK)
// 翻訳可能な文字列の一覧をここに定義する。

import { Book, Message } from "@hi18n/core";
import catalogEn from "./en";
import catalogJa from "./ja";

export type Vocabulary = {
  // 凡例: "翻訳ID": Message<{ 引数 }>; (引数がないときは単に Message でOK)
  "example/greeting": Message<{ name: string }>;
};

// 各言語の翻訳データをまとめたオブジェクト
export const book = new Book<Vocabulary>({
  en: catalogEn,
  ja: catalogJa,
});
// src/locale/en.ts
// (他の名前でもOK)
// 各言語での翻訳をここに定義する。

import { Catalog, msg } from "@hi18n/core";
import type { Vocabulary } from ".";

export default new Catalog<Vocabulary>({
  // 凡例: "翻訳ID": msg(翻訳文字列),
  "example/greeting": msg("Hello, {name}!"),
});
// src/locale/ja.ts (enと同様)

import { Catalog, msg } from "@hi18n/core";
import type { Vocabulary } from ".";

export default new Catalog<Vocabulary>({
  "example/greeting": msg("こんにちは、{name}さん!"),
});

翻訳IDの同期のためのコマンドを用意します。

// package.json
{
  "scripts": {
    "i18n:sync": "hi18n sync 'src/**/*.ts' 'src/**/*.tsx'"
  }
}

これで基本の導入は完了です。 (ESLintを設定している場合はESLint pluginの設定もおすすめしていますが、導入方法の説明は省略します)

翻訳の呼び出し

定義した翻訳を呼び出すにはいくつかの方法があります。

useI18n を使う方法

Reactを使う場合の基本の方法です。まずルート付近でロケールを設定します。

// 自前でReactDOMを呼んでいる場合の例
import { LocaleProvider } from "@hi18n/react";

const root = ReactDOMClient.createRoot(/* ... */);
root.render(
  <LocaleProvider locales="ja">
    {/* ... */}
  </LocaleProvider>
);

利用側ではuseI18nを呼び出します。

import { useI18n } from "@hi18n/react";
// 最初に定義したBookインスタンス (翻訳データ) を明示的にimportする
import { book } from "../../locale";

const Greet: React.FC = () => {
  // 現在のロケールと指定したbookを使った翻訳を開始する
  const { t } = useI18n(book);
  return <>{t("example/greeting", { name: "太郎" })}</>;
};

getTranslatorを使う方法

Reactに依存しない方法です。ロケール情報は自前で管理する必要があります。

import { getTranslator } from "@hi18n/core";
// 最初に定義したBookインスタンス (翻訳データ) を明示的にimportする
import { book } from "../../locale";

const { t } = getTranslator(book, "en");
console.log(t("example/greeting", { name: "太郎" }));

<Translate> を使う方法

<Translate> はReactの要素を含むコンテンツの翻訳に適した方法です。

import { Translate } from "@hi18n/react";
// 最初に定義したBookインスタンス (翻訳データ) を明示的にimportする
import { book } from "../../locale";

const Greet: React.FC = () => {
  return <Translate book={book} id="example/greeting" name="太郎" />;
};

<Translate> では翻訳の引数としてReactの要素を渡すことができます。

const UnreadMessages: React.FC = () => {
const unreadCount = 2;
if (unreadCount === 0) return null;

// en: "You have <link>{count,plural,one{# unread message}other{# unread messages}}</link>"
// ja: "<link>{count,number}通の未読メッセージ</link>があります"
return <Translate book={book} id="example/unread" count={unreadCount}>
<a key="link" href="https://example.com/inbox" />
</Translate>;
};

翻訳IDを同期する

hi18n sync コマンドを使うことで翻訳IDを同期できます。

hi18n sync <globs...> [--exclude <glob>]

たとえば、package.jsonで以下のようにコマンドを定義している場合

// package.json
{
  "scripts": {
    "i18n:sync": "hi18n sync 'src/**/*.ts' 'src/**/*.tsx'"
  }
}

次のようにして翻訳IDの同期を行えます。

npm run i18n:sync

# または:

yarn i18n:sync

この処理はプロジェクト中のTypeScript/JavaScriptソースを書き換えるので注意してください。これにより以下の2つの作業が行われます。

  • 使われていない翻訳の削除 (コメントアウト)
  • 必要だが定義されていない翻訳のためのコードを生成

もし誤って利用箇所を消してしまい、翻訳がコメントアウトしてしまっても戻すのは簡単です。利用箇所を戻して再度同期処理を行えば、コメントの中身から翻訳が復元されます。

翻訳の同期処理は翻訳の型部分 (Message<{ ... }>{ ... } の部分) に関してはノータッチです。ここはプログラマーが直接編集することが想定されています。

--check オプションをつけると、変更が必要なときに変更を適用するのではなくエラーにすることができます。これはGitHub ActionsなどのCIで同期がとれていることを確認するのに便利です。

npm run i18n:sync --check

# または:

yarn i18n:sync --check

翻訳IDを追加する

新しい翻訳が必要なとき、手動でそれらを追加してもいいですが、ある程度ツールに任せることもできます。

コードを書くときに、 t のかわりに t.todo を使い、 Translate のかわりに Translate.Todo を使うようにします。

t.todo("example/new");
<Translate.Todo book={book} id="example/new" />;

その後同期を行い、翻訳の中身を追加したら "TODO" を削除します。

その他できること

  • 複数形による分岐と数値フォーマット。 Intl が使える環境である必要があります。
  • 複数の翻訳IDから動的に内容を選択するには `t.dynamic` または `Translate.Dynamic` を `translationId` と組み合わせて使います。
  • ESLintプラグイン `@hi18n/eslint-plugin` を使うことで、hi18nの正しい使い方をある程度強制することができます。
    • Linguiからの移行支援用のルールなども含まれています。
  • ページやコンポーネント単位で翻訳データを分割するには、単に複数の独立したBookインスタンスを作ればOKです。あとはモジュールバンドラーがうまくやってくれるはずです。

次に読む

hi18n (i18nライブラリ) の使い方: メッセージフォーマット編 | Wantedly Engineer Blog
hi18n は現在Wantedlyで開発中の、 TypeScript/JavaScript向け翻訳テキスト管理ライブラリ ( i18nライブラリの一種) です。 基本の使い方は以下の記事で説明しています。 本稿では発展的な使い方として、メッセージフォーマットの構文を紹介します。 詳細な説明に入る前に、メッセージフォーマットでできることを大まかに紹介します。 波括弧で引数名を囲むことで、動的に生成された文字列を間に挟むことができます。引数名のかわりに番号を入れることもできます。 文字列のかわりに数値や日付時
https://www.wantedly.com/companies/wantedly/post_articles/407312
hi18n (i18nライブラリ) 入門&紹介シリーズ目次 | Wantedly Engineer Blog
hi18n は現在Wantedlyで開発中の、TypeScript/JavaScript向け翻訳テキスト管理ライブラリ (i18nライブラリの一種) です。https://github.com/...
https://www.wantedly.com/companies/wantedly/post_articles/406614
Invitation from Wantedly, Inc.
If this story triggered your interest, have a chat with the team?
Wantedly, Inc.'s job postings
13 Likes
13 Likes

Weekly ranking

Show other rankings
Like Masaki Hara's Story
Let Masaki Hara's company know you're interested in their content