【第537回】 Agentforce : ブラウザ言語に応じた拡張チャットの多言語表示
本記事では、サービスエージェントを外部 Web サイトに表示した場合に、ブラウザ言語に合わせてチャットを多言語化する方法を書いておきます。
これにより、例えばサービスエージェント 拡張チャット v2 の「Ask Me Anything」のテキストなどを、利用者の言語に合わせて表示できるようになります。
また、今回はさらに一歩進めて、Lightning Type を利用して独自の Lightning Web Component(LWC)をチャット内に表示している場合の多言語対応についても触れます。
実際に検証してみると、チャット本体の多言語化と Lightning Type の多言語化は、少し分けて考える必要がありました。
本記事では特定の実装手順というよりも、Agentforce の多言語化を実装する際に確認しておきたいポイントとして整理します。

補足: 私がサポートに確認したところ、現時点では「エージェント名」の多言語化には対応していないようです。そのため、多言語対応が必要な場合は、英語のエージェント名を設定しておくのが無難でしょう。今後のリリースで対応されることを期待したいですね。
翻訳言語設定
1. 設定で「翻訳言語設定」を検索し、機能が有効化されていない場合は有効化します。

2. 言語を追加していきます。

3. 今回、「英語」「日本語」「韓国語」「中国語(簡体字)」「中国語(繁体字)」を作成するので、まず「英語」を登録し、Active にチェックを入れ、翻訳者としてユーザーを選択します。

翻訳者とは、その言語の翻訳を作成・編集できるユーザーのことです。
4. 「日本語」「韓国語」「中国語(簡体字)」「中国語(繁体字)」を同じように設定します。

Messaging Settings の設定
次に、Agentforce / Enhanced Chat 側で利用者の言語を認識できるようにします。
ここで重要なのが、設定 > Messaging Settings の
Identify preferred language of messaging users
です。
設定から、現在 Agentforce で利用している「Messaging Settings(メッセージング設定)」を開き、Identify preferred language of messaging users にチェックを入れます。

この設定を有効にすることで、Messaging 側で利用者の優先言語を扱えるようになります。
今回のようにブラウザ言語に応じて Agentforce を多言語化する場合は、単純にチャット画面のラベルを翻訳するだけではなく、Messaging 側にも利用者の言語を認識させることが重要です。
拡張チャット v2 の表示ラベルを設定
1. 設定 >「組み込みサービスリリース」に移動し、拡張チャット v2 で「カスタム表示ラベルを設定」をクリックします。

2. まず言語を「日本語」に切り替えて、チャットグループで「一般」を選択します。

3. 表示ラベルグループで「すべて」を選択します。

4. 表示ラベル種別を Standard にすると、設定可能な一覧が表示されます。カスタム表示ラベルを入力して「保存」します。もちろん、標準の表示ラベルで問題なければ標準のままでも問題ありません。
今回は「Ask Me Anything」のボタンに該当する「何か質問してください」を「ご用件に合わせてご案内します」に変更します。

5. すべてのテキストを編集できたら「完了」をクリックして終了します。

6. 他の言語でも同じように設定します。

Experience Cloud のサイト言語を設定
続いて、Enhanced Chat で利用される Experience Cloud / LWR 側についても、使用する言語を設定しておきます。
1. 対象サイトを All Sites > Builder で開きます。

2. Settings > Languages を開いて、編集ボタンから、利用する言語を Site Languages に追加します。

3. 例えば、日本語を使用するのであれば、日本語が Active になっていることを確認します。必要に応じて、フォールバック言語も設定します。

4. 設定が完了したら、サイトを Publish します。ここは忘れやすいポイントですので必ず Publish してください。

コードスニペットの変更
1. 「組み込みサービスリリース」からコードスニペットを取得します。

2. 通常は、以下のようなコードになっていると思います。
<script type='text/javascript'>
function initEmbeddedMessaging() {
try {
embeddedservice_bootstrap.settings.language = 'en_US';
embeddedservice_bootstrap.init(
'YOUR_ORG_ID',
'YOUR_DEPLOYMENT_NAME',
'YOUR_SITE_URL',
{
scrt2URL: 'YOUR_SCRT2_URL'
}
);
} catch (err) {
console.error(
'Error loading Embedded Messaging: ',
err
);
}
}
</script>
<script
type='text/javascript'
src='YOUR_BOOTSTRAP_URL'
onload='initEmbeddedMessaging()'>
</script>3. このコードを、以下のように変更します。
<script type='text/javascript'>
function initEmbeddedMessaging() {
try {
const userLang =
(
navigator.language ||
navigator.userLanguage ||
'en'
).toLowerCase();
let chatLang = 'en_US';
if (userLang.startsWith('ja')) {
chatLang = 'ja';
} else if (userLang.startsWith('ko')) {
chatLang = 'ko';
} else if (
userLang.startsWith('zh-cn') ||
userLang.startsWith('zh-sg')
) {
chatLang = 'zh_CN';
} else if (
userLang.startsWith('zh-tw') ||
userLang.startsWith('zh-hk') ||
userLang.startsWith('zh-mo')
) {
chatLang = 'zh_TW';
}
embeddedservice_bootstrap.settings.language =
chatLang;
embeddedservice_bootstrap.settings.useHostSiteLanguage =
true;
embeddedservice_bootstrap.init(
'YOUR_ORG_ID',
'YOUR_DEPLOYMENT_NAME',
'YOUR_SITE_URL',
{
scrt2URL: 'YOUR_SCRT2_URL'
}
);
} catch (err) {
console.error(
'Error loading Embedded Messaging: ',
err
);
}
}
</script>
<script
type='text/javascript'
src='YOUR_BOOTSTRAP_URL'
onload='initEmbeddedMessaging()'>
</script>主に重要なのは、以下の部分です。
const userLang =
(
navigator.language ||
navigator.userLanguage ||
'en'
).toLowerCase();ここでブラウザの言語を取得します。
そして、
if (userLang.startsWith('ja')) {
chatLang = 'ja';
} else if (userLang.startsWith('ko')) {
chatLang = 'ko';
}のように、取得した値から Agentforce で利用する言語を決定します。
最後に、
embeddedservice_bootstrap.settings.language =
chatLang;へ設定します。
useHostSiteLanguage も設定する
そして、今回、特に重要なのが、こちらです。
embeddedservice_bootstrap.settings.useHostSiteLanguage =
true;Enhanced Chat 内部で利用される LWR 側にも、ホストサイトで決定した言語を引き継ぐために設定します。
今回の私の検証では、
ブラウザ言語
↓
settings.language
↓
Enhanced Chat
↓
内部 LWR
↓
Lightning Type / LWC
という形で言語を連携させるために、この設定が重要でした。
特に Lightning Type などの独自 UI を利用する場合は、ここも確認しておくとよいでしょう。
ブラウザ言語コードの違いに注意
ブラウザが返す言語コードは環境によって異なります。
例えば、日本語でも、
ja
ja-JP
のような違いがあります。
韓国語でも、
ko
ko-KR
などがあります。
さらに中国語では、
zh-CN
zh-SG
zh-TW
zh-HK
などがあり、簡体字と繁体字を区別する必要があります。
そのため、
userLang === 'ja'のような完全一致ではなく、
userLang.startsWith('ja')のように判定しておく方が扱いやすいと思います。
この部分については、利用したい言語とデフォルト言語を指定して生成 AI にコードを作ってもらうのもよいでしょう。
4. 完成後は、変更したコードを外部 Web サイトに埋め込めば完了です。

Lightning Type を利用する場合
Agentforce では Lightning Type を利用して、会話の途中に独自の Lightning Web Component を表示できます。
例えば、ユーザーに何らかの商品を選択してもらうために、検索文字列を入力すると候補が表示される「サジェスト入力」を独自 LWC として作成しているとします。

このような場合、Embedded Messaging の表示言語を切り替えただけでは、独自 LWC 内に実装した文字列まですべて自動的に翻訳されるわけではありません。
ここは別途対応する必要があります。
LWC 側でも表示言語を判定する
Lightning Web Component では、
@salesforce/i18n/langを利用して言語を取得できます。
例えば、
import LANG from '@salesforce/i18n/lang';
get isJapanese() {
return (
LANG &&
LANG.toLowerCase().startsWith('ja')
);
}のように判定します。
そのうえで、独自 LWC 内の表示ラベルを切り替えます。
例えば、
get inputLabel() {
return this.isJapanese
? '商品を検索'
: 'Search for a product';
}
get searchLabel() {
return this.isJapanese
? '商品名を入力'
: 'Enter a product name';
}
get searchingLabel() {
return this.isJapanese
? '検索中...'
: 'Searching...';
}といった形です。
これによって、
日本語
商品を検索
商品名を入力
検索中...
英語
Search for a product
Enter a product name
Searching...
のように、同じ Lightning Type / LWC で表示を切り替えられます。
【日本語の Lightning Type】

【英語の Lightning Type】

表示するデータ自体も多言語化する
例えば、検索候補となるデータに、
日本語名称
英語名称
の両方が存在するとします。
日本語の場合は日本語名称、英語の場合は英語名称を表示すれば、検索結果自体についても多言語化できます。
例えば、
get selectedItemName() {
if (this.isJapanese) {
return (
this.selectedItemNameJa ||
this.selectedItemNameEn
);
}
return (
this.selectedItemNameEn ||
this.selectedItemNameJa
);
}のようにできます。
英語名称が存在しない場合は日本語名称へフォールバックするといった処理も可能です。
Lightning Type から返す値にも注意
画面上では正しい言語で表示できていても、Lightning Type から Agentforce に返却する値についても注意が必要です。
例えば、日本語名称だけを返しているとします。
this._value = {
recordId: this.selectedRecordId,
itemCode: this.selectedItemCode,
itemNameJa: this.selectedItemNameJa
};この場合、英語画面で英語名称を表示できていたとしても、Submit 後などに値が再度コンポーネントへ渡された際、英語名称を復元できなくなる可能性があります。
そのため、必要であれば、
this._value = {
recordId: this.selectedRecordId,
itemCode: this.selectedItemCode,
itemNameJa: this.selectedItemNameJa,
itemNameEn: this.selectedItemNameEn
};のように、両方の値を保持します。
ここは単純な「翻訳」とは少し違います。
多言語化では、画面に何を表示するかだけではなく、その後の処理にどの言語データを引き継ぐのかまで考える必要があります。
Lightning Type のデータ構造にも注意
Lightning Type で Apex Class Type を利用している場合は、LWC だけではなく、そのデータ構造についても確認します。
例えば、概念的には以下のような Schema を利用します。
{
"title": "Item Selection",
"description": "Selected item from the search results.",
"lightning:type": "@apexClassType/c__ItemSelection"
}Editor から独自 LWC を呼び出す場合は、例えば以下のようになります。
{
"editor": {
"componentOverrides": {
"$": {
"definition": "c/itemSuggestionInput"
}
}
}
}この場合、
LWC
↓
Lightning Type
↓
Apex Class Type
↓
Agentforce
というデータの流れの中で、多言語表示に必要な情報を失わないようにします。
例えば、日本語名称と英語名称の両方を使用するのであれば、それらを必要な箇所まで保持できるデータ構造にしておく必要があります。
Agentforce の回答言語にも注意
Lightning Type の UI が英語になっていても、Agentforce が日本語で回答してしまっては、ユーザーから見ると不自然です。
逆に、
Agentforce → 英語
Lightning Type → 日本語
という状態も避けたいところです。
そのため、Agentforce 側についても、現在のユーザーの言語に応じて回答するよう設計します。
今回の検証では、言語コードを Agentforce 側でも保持し、
ja → 日本語で回答
en → 英語で回答
のように回答言語を制御しました。
ここで注意したいのは、言語制御の指示を複雑にしすぎないことです。
今回の検証でも、Lightning Type の表示制御と言語制御について細かい指示を重ねすぎると、意図しない動作になるケースがありました。
そのため、
「現在の言語コードに従って回答する」
という基本ルールを明確にしたうえで、Lightning Type の呼び出しロジックとはできるだけ分離しておく方が扱いやすいと思います。
多言語化はレイヤーごとに考える
今回の検証を通して、一番重要だと感じたのがこの点です。
Agentforce の多言語化は、一つの設定だけですべてを切り替えるものではありません。
今回の構成では、大きく以下のように考えると整理しやすくなりました。
ブラウザ言語
↓
Embedded Messaging
↓
Messaging User Language
↓
Agentforce
↓
Enhanced Chat / LWR
↓
Lightning Type
↓
独自 LWC
↓
LWC が保持・返却するデータ
例えば、
「チャットのボタンだけ英語」
「Agentforce の回答だけ日本語」
「Lightning Type だけ英語」
「選択時は英語だったのに Submit 後に日本語になる」
といった現象が発生した場合、すべてを同じ「多言語化の問題」として考えると、原因を見つけるのが難しくなります。
どのレイヤーで言語がずれているのかを確認することが重要です。
実際に試す
ブラウザ言語を変更して動作確認する場合、Google Chrome であれば、アドレスバーに以下を入力します。
chrome://settings/languagesその後、表示言語を切り替えて、チャットボタンやチャットウィンドウの表示が変わるか確認してください。
以下のように、ブラウザ言語に応じてチャット表示が切り替われば成功です。
英語の場合

日本語の場合

韓国語の場合

中国語(簡体字)の場合

中国語(繁体字)の場合

いかがでしたでしょうか。
今回の内容は検索してもなかなか見つからなかったため、私の方でメモとして残しておきました。
Agentforce のチャットを多言語で提供する場合、ブラウザ言語に応じて表示言語を切り替える対応は非常に重要です。
特に、日本語・英語・韓国語・中国語など、複数言語に対応する企業では、実装しておきたい設定だと思います。
今回は以上です。
