以前から、日本語のコンテンツを英語に自動翻訳して提供する仕組み(外部サービスに依存)がありましたが、より意図通りに翻訳したコンテンツを出せるようにするために、元のコンテンツに言語別の情報を持たせて出し分けられるようにする改修を実施しました。 同時並行で、コンテンツ作成ツール自体のリファクタリング(コード改修、ビルド工程見直し)も実施することで、コンテンツ作成ツールの保守性・拡張性を高めるとともに、コンテンツ作成の生産性を高めることを目指しました。 最小工数かつ安全な実施を最優先に、コンテンツ作成ツール、バックエンドそれぞれで改修を実施しています。 既存のコンテンツ作成ツールは、多言語対応しない(日本語情報のみの)コンテンツを生成していましたが、今回は多言語の情報を持ったコンテンツを生成してDBに挿入するように改修しています。 コンテンツに言語別の情報を持たせるためには、コンテンツのテンプレートデータ構造を定義・生成した上で、テンプレートオブジェクト内を再帰的に走査して言語別の情報が必要なパラメータ(ex: コンテンツのタイトル、テキスト等)に日本語・英語・...と言語ごとに情報を追記することで、多言語情報を持ったオブジェクトとしてMongoDBに登録することとします。 バックエンド側は上記の逆で、MongoDBから取得した多言語対応版コンテンツ情報の中身を再帰的に走査し、あらかじめ指定された一言語のみの情報を持つコンテンツ情報のみにデコードすることで、従前と同じデータ構造のオブジェクトを使いまわせるようにします。 再帰を使うことで、コンテンツ作成ツール・バックエンド側それぞれ十数行程度のコードの組み合わせにて簡潔に実装されます。DBの入出力周り(コンテンツ作成ツール、Repository)で多言語対応の面倒事を全て巻き取り切ったため、フロントエンドと(DB取得以外の)バックエンドのビジネスロジックにおいてほとんど変更が出ない(変更があったことを知らなくてよい)形です。 多言語対応が必要なパラメータに適用する型を定義します。以下はコードの一部で、 コンテンツ作成元データ(CSV, Jupyterファイル等)から、国際化対応したドキュメントを生成して、Mongoに挿入します。この手順自体は従前を踏襲していますが、CSVおよびJupyterファイルは別言語版をあらかじめ用意してあります。 以下は型情報を頼りにして、再帰的にテンプレートを走査して言語別情報を詰め込むソースコード(の一部)です。 ※ バックエンド側はほぼ上記の逆なので、割愛します シンプルな再帰実装を使う方針が奏功し、多言語対応自体はほぼ最小工数で要件を達成して安全なリリースを実現できました。加えて、コンテンツ作成チームからの要望を取り込みながらの改修作業、仕様のヒアリングと紐解き・再構築、安全なリリースに向けた手順組んだ結果、多言語対応自体の外でも価値が実現されています。 例えば以下の通りです。
目的
方針
コンテンツ作成ツールの改修
バックエンドの改修
まとめ
実装の手順
kind: LANGUAGE
を持っていれば国際化対応パラメータとして扱わせたいための型です。export const LANGUAGE = 'LANGUAGE' as const;
export interface ILang<T extends string | string[]> {
kind: typeof LANGUAGE;
data: {
lang: Lang;
text: T;
}[];
}
const rec = (lang, source, template) => {
if (source == null) return source;
if (template && template['kind'] === LANGUAGE) {
template['data'].push({ lang, text: source });
return template;
}
if (typeof source !== 'object' || !Object.keys(source).length) return source;
if (Array.isArray(source)) return source.filter(elm => elm !== undefined && elm !== null).map((elm, i) => rec(lang, elm, deepcopy(template[i] || template[0])));
return Object.fromEntries(Object.keys(source).map(key => [key, rec(lang, source[key], template[key])]));
}
意義