
多言語・翻訳は種類ごとに別テーブル(sys_translated_text)
ServiceNow を日本語で使っていると、画面のラベルもメッセージも日本語で出てきます。その翻訳テキストは1つのテーブルにまとまっておらず、「何を翻訳するか」によって別々のテーブルに分かれています。

翻訳は、対象の種類によって次のテーブルに分かれます。
UIメッセージ … sys_ui_message(Message)
レコードの長文 … sys_translated_text(Translated Text)
テーブル名やフィールド値 … sys_translated(Translated Name / Field)
この3つを PDI 実機で開くと、翻訳を引く鍵(key / documentkey / element)が3者3様でした。役割・主要フィールド・言語の持ち方を確認します。
ServiceNow の Incident は触ったことがあるが、翻訳がどのテーブルで動くかはまだ知らない管理者・開発者を想定しています。
この記事で分かること
ServiceNow の翻訳が「対象の種類ごと」に別テーブルへ分かれていること
sys_ui_message(メッセージ)/ sys_translated_text(長文の値)/ sys_translated(テーブル名・フィールド値)の使い分け
各テーブルが「翻訳をどの鍵で引くか」(key か、tablename+fieldname か など)
言語コード(language)が各レコードに付いて表示が切り替わること
既定言語(英語)と「上書きの翻訳」の持ち方の違い
実機で確認するときに見るべき一覧URL
この記事の内容は ServiceNow の PDI(Personal Developer Instance)Zurich(ズーリッヒ)リリースの OOTB(初期設定)で確認した個人メモです。本番環境やカスタマイズ済み環境、追加の言語パックを入れた環境では、テーブルの件数・言語分布・設定の内容が異なる場合があります。
ServiceNow の多言語(翻訳)とは
ServiceNow の多言語対応(ローカリゼーション / i18n)は、同じ画面・同じレコードを、ユーザーの言語設定に合わせて別の言語で表示します。ユーザーごとに言語を持ち、表示のたびにその言語の翻訳を探して差し替えます。
翻訳テキストは「翻訳専用のテーブル」に、言語コード(language)付きのレコードとして保存されます。元のデータを書き換えるのではなく、言語ごとに翻訳レコードを足していきます。どのテーブルに何の翻訳が入るかを知っておくと、「この文言はどこを直せば変わるのか」をたどれます。
PDI(Zurich / OOTB)では、翻訳の対象は1つのテーブルに集約されず、種類ごとに別テーブルへ分かれていました。

公式ドキュメントでも、言語パックがこれらの翻訳テーブル群を埋めて多言語対応が成り立つと説明されています。ここからは代表的な3つ(sys_ui_message / sys_translated_text / sys_translated)を実機で開きます。
3つの翻訳テーブルの使い分け
主要な翻訳テーブルは「何を翻訳し、何を鍵にして引くか」で役割が分かれます。

PDI(Zurich / OOTB)では、次のように役割が分かれていました。ラベルは画面上の表示名で、実機どおり記載します。

sys_ui_message(Message) … スクリプトやUIで出る「メッセージ」を翻訳します。元のメッセージ文字列(key)と言語(language)で引き、翻訳後(message)を返します。
sys_translated_text(Translated Text) … 特定レコードの長文・リッチテキストの「値そのもの」を翻訳します。どのテーブル(tablename)のどのフィールド(fieldname)のどのレコード(documentkey)か、まで指定して引きます。
sys_translated(Translated Name / Field) … テーブル名やフィールドの値といった「名前・フィールド」を翻訳します。テーブル(name)とフィールド(element)で引きます。
ラベルと選択肢は別のテーブル
このほか、フィールドの「ラベル」は sys_documentation(Field Label、固有フィールド10・sys_metadata を継承)、選択肢は sys_choice が担当します。文言が変わらないときは、その文言がメッセージか・レコードの値か・ラベルかを先に見極め、対応するテーブルを開きます。
参考: Translation tables(Zurich)。各翻訳テーブルが何を担当するかが一覧されています。
sys_ui_message(メッセージの翻訳)
sys_ui_message は、スクリプトやUIで表示するメッセージ文字列の翻訳を持ちます。PDI(Zurich / OOTB)では固有フィールドが7つでした。

中心になるのは key(元のメッセージ)・message(翻訳後)・language(言語)の3つです。同じ key に言語ごとのレコードを持たせて、表示を切り替えます。ほかに code(コード分類)・application(アプリケーションスコープ)・commented_message(コメント用のメモ)といった固有フィールドもあります。
実機でフランス語(fr)のレコードを開くと、key が New Tab {0}、message が Nouvel Onglet {0} でした。{0} は後から値を差し込むプレースホルダで、翻訳しても残ります。

メッセージを引く流れは次のようになります。

英語が大半を占める理由
PDI で sys_ui_message を言語で集計すると、全7,875件のうち7,870件が en(英語) で、他言語はごくわずかでした。この PDI は英語パックのみ稼働しており(sys_language で active なのは English だけ)、英語が大半を占めます。英語のレコードでは key と message が同じ文字列で(key も message も No, close it)、英語は素通し、他言語のときだけ翻訳レコードを使う、という構造でした。

メッセージ一覧は、次のURLで確認できます(先頭の <YourInstance> は自分のインスタンスに置き換えてください)。
https://<YourInstance>/sys_ui_message_list.dosys_ui_message にひも付く設定は Business Rule が1件、Access Controls が12件(テーブル・フィールド計)でした。触る機会は少なく、フォームから直接編集するというより言語パック側から生成されるレコードです。
いま新しくメッセージ翻訳を足すなら
あるメッセージをフランス語で出したいときは、sys_ui_message に1レコードを追加します。さきほどの fr レコードがその設定例で、フォームに次の値を入れます。
key … 元のメッセージ文字列(例:New Tab {0})。en レコードの key と一致させる
language … 出したい言語コード(例:fr)
message … その言語の表示文字列(例:Nouvel Onglet {0})。{0} は位置を変えても残す
key と language の組で1レコードになるので、同じ key に対して言語ごとに足していけば、ユーザーの言語設定に応じて message が切り替わります。
sys_translated_text(レコードの長文・値の翻訳)
sys_translated_text は、特定レコードの特定フィールドの「値そのもの」を翻訳して保持します。メッセージのようにキーで引くのではなく、どのテーブル・どのフィールド・どのレコードかまで指定します。PDI(Zurich / OOTB)では固有フィールドが11でした。中心となるのは tablename(対象テーブル)・fieldname(対象フィールド)・documentkey(対象レコードの sys_id)・language(言語)・value(翻訳後)の5つです。
このテーブルは言語の持ち方が他と違います。PDI で sys_translated_text を言語でグループ化すると、英語パックしか入っていないのに、20を超える言語のレコードが最初から入っていました。

合計838件は、20以上の言語に分かれていました。
言語ごとの内訳

件数の内訳は次のとおりです。
fr=61, zh=49, es=45, he=39, ja=38, de=34, it=34, nl=34, pt=33, ar=33
cs=32, fi=32, ko=32, pl=32, ru=32, sv=32, th=32, tr=32, hu=32, nb=32fr(フランス語)が61件で最多ですが、cs・fi・ko・pl・ru・sv・th・tr・hu・nb は軒並み32件で並んでいます。言語パックの初期データは、言語ごとに大きく偏らせず、ほぼ同じ分量で用意されているようです。
なぜ en が0件なのか
en(英語)のレコードは0件でした。Translated Text は既定言語(英語)の値を二重に持たず、既定言語以外の言語に対する上書きだけを保存します。元の英語値は対象レコード側(そのカタログ項目やトピックのレコード本体)にあり、他言語のときだけ sys_translated_text の value を使う分担です。
実機のサンプルでは、tablename=sys_declarative_action_assignment / fieldname=label / language=ko / value=오픈 という値が入っていました。あるレコードの label を、韓国語ではこう表示する、という形です。
参考: Translated Text(Zurich)。長文・リッチテキストの値を言語別に翻訳する仕組みが説明されています。
Translated Text 一覧は、次のURLで確認できます。
https://<YourInstance>/sys_translated_text_list.do?sysparm_query=GROUPBYlanguagesys_translated_text にひも付く設定は Business Rule が1件、Access Controls が3件でした。
sys_translated(テーブル名・フィールド値の翻訳)
sys_translated(ラベル:Translated Name / Field)は、テーブル名やフィールドの値を翻訳します。PDI(Zurich / OOTB)では固有フィールドが7で、中心は name(対象テーブル)・element(対象フィールド)・label / value(翻訳後)・language(言語)です。
sys_translated_field という名前に注意
「翻訳対象フィールド(sys_translated_field)」という名前を聞くことがありますが、PDI(Zurich / OOTB)に sys_translated_field というテーブルは存在しませんでした(sys_db_object で検索しても0件)。実体はこの sys_translated(Translated Name / Field)です。名前を混同しないよう注意します。
PDI で sys_translated は153件ありました。実機のサンプルでは、name=sys_cs_branding_setup / element=menu_title / language=en / value=Contact Support という値が入っていました。あるテーブルのあるフィールドの表示名を、この言語ではこう出す、という形です。

参考: Translated Name / Field table(Zurich)。このテーブルが扱う対象が説明されています。
一覧は、次のURLで確認できます。
https://<YourInstance>/sys_translated_list.do3テーブルの位置づけ(テーブル定義で確認)
3つのテーブルがプラットフォーム上でどう定義されているかも実機で確認できます。PDI(Zurich / OOTB)では次のとおりでした。
sys_ui_message … super_class = sys_metadata(Application File)を継承。アプリ構成として配布される。
sys_translated(Translated Name / Field)… super_class = sys_metadata を継承。
sys_translated_text … super_class が空で、sys_metadata を継承しない独立したテーブルです。
UIメッセージと Name/Field 翻訳はアプリ構成(メタデータ)の一部として扱われ、Translated Text だけは別系統のテーブルになっています。アプリ構成側の2つ(sys_ui_message/sys_translated)は、スコープやアプリと一緒に Update Set で運搬できる設計です。一方 Translated Text は対象レコードの言語ごとの値そのものなので、アプリの構成というよりレコードのデータに近い扱いです。super_class の違いは、「アプリの一部として配布するか、レコードのデータとして扱うか」という設計方針の表れだと考えられます。
https://<YourInstance>/sys_db_object_list.do?sysparm_query=name=sys_ui_message^ORname=sys_translated_text^ORname=sys_translated
sys_ui_message の固有フィールドは、次のURLで一覧できます。
https://<YourInstance>/sys_dictionary_list.do?sysparm_query=name=sys_ui_message^elementISNOTEMPTY
ServiceNow の翻訳テーブルのまとめ
ServiceNow の翻訳は1つのテーブルに集約されず、「何を翻訳するか」で別テーブルに分かれます。メッセージは sys_ui_message、レコードの長文の値は sys_translated_text が担当します。テーブル名・フィールド値は sys_translated、ラベルは sys_documentation、選択肢は sys_choice です。
sys_ui_message は key(元テキスト)+ language で引き、message を返します。{0} などのプレースホルダは翻訳後も残ります。
sys_translated_text は tablename+fieldname+documentkey+language という細かい鍵で、特定レコードの値を翻訳します。PDI では en=0 で、既定言語以外の上書きだけを持っていました。
sys_translated は name(Table)+element+language で、テーブル名・フィールド値を翻訳します。
sys_translated_field というテーブルは PDI(Zurich / OOTB)に存在しませんでした。実体は sys_translated(Translated Name / Field)です。
各レコードは language コードを持ち、ユーザーの言語に合わせて表示が切り替わります。英語パックのみの PDI でも、sys_translated_text には最初から20以上の言語のレコードが同梱されていました。
文言を直すときは、その文言がメッセージか・レコードの値か・ラベルかを先に見極め、対応するテーブルを開いて language で絞り込みます。
実機で気づいたこと
「翻訳対象フィールド(sys_translated_field)」という名前を最初に聞いたとき、そのままの名前のテーブルを探しました。ですが PDI には存在せず、実体は sys_translated(Translated Name / Field)でした。ドキュメントや会話で聞く通称と、実際のテーブル名が一致しないことがある、という良い例です。
sys_ui_message は英語のレコードも普通に持っていて全7,875件のうち7,870件が en でしたが、sys_translated_text は en が0件でした。最初はどちらも「既定言語は別の場所にあるから翻訳テーブルには不要」という同じルールだろうと思っていましたが、実機で見ると方針が逆でした。sys_ui_message は全言語分をこのテーブルに集約する設計、sys_translated_text は既定言語以外の上書きだけを持つ設計で、同じ「翻訳テーブル」でもデータの持ち方が違います。実務でメッセージを追加するときは既定言語の行も含めて sys_ui_message に作る一方、既存レコードの値を翻訳するときは sys_translated_text に英語の行は作らない、と覚えておくと迷いません。
参考に sys_documentation(フィールドラベルの翻訳)の件数を見ると143,855件で、sys_ui_message の7,875件(約18倍)や sys_translated の153件と桁が違いました。ラベルはテーブルの数×フィールドの数だけ発生しうるので、対象の母数が翻訳系テーブルの中でも突出して多いのだと考えられます。
次に読むなら
次に確認したいのは、次の3点です。
フィールドラベルを翻訳する sys_documentation(Field Label)
選択肢を翻訳する sys_choice
言語パックを追加したときに各テーブルがどう埋まるか
Localization Framework(自動翻訳)や Dynamic Translation も翻訳を効率化します。ユーザー言語の切り替えがどのテーブルのどのレコードを参照して実現されるかを実機で追うと、多言語運用の設計が見通せます。これらは別記事で扱う予定です。
用語
PDI:Personal Developer Instance(無料の検証用インスタンス)
OOTB:Out of the Box(初期設定のまま)
i18n:Internationalization(国際化 / 多言語対応)
ローカリゼーション:ユーザー言語に合わせて表示を切り替えること
language(言語コード):en(英語)/ ja(日本語)/ fr(フランス語)など
既定言語(Default language):システムの基本言語。今回の PDI では英語(en)
言語パック(Language Pack):ある言語の翻訳データをまとめてインストールする単位
自分の環境で確認するときのURL
先頭に自分のインスタンスを付けると、同じ画面が開けます。
テーブル定義 : sys_db_object_list.do?sysparm_query=name=sys_ui_message^ORname=sys_translated_text^ORname=sys_translated
UIメッセージ一覧 : sys_ui_message_list.do
Translated Text : sys_translated_text_list.do?sysparm_query=GROUPBYlanguage
Translated Name/Field: sys_translated_list.do
sys_ui_message 固有 : sys_dictionary_list.do?sysparm_query=name=sys_ui_message^elementISNOTEMPTY検証範囲とおことわり
確認した範囲は次のとおりです。
3つの翻訳テーブル(sys_ui_message / sys_translated_text / sys_translated)の super_class、固有フィールド数
主要フィールドと役割
レコード件数、言語分布
sys_ui_message / sys_translated_text の周辺設定件数
sys_language の active 言語、実機サンプル値
sys_translated_field が存在しないこと
すべて PDI(Zurich / 2026-06-22 確認)の OOTB で取得しています。
確認していない範囲(断定しません)は次のとおりです。
言語パックを追加したときの各テーブルの埋まり方
gs.getMessage() / getMessage() などランタイムでの翻訳解決の挙動
Localization Framework(自動翻訳)や Dynamic Translation の動作
Service Portal / UI Builder での表示
各 Business Rule の内部処理
これらは検証範囲外です。
今回は PDI の OOTB(初期設定・英語パックのみ稼働)を前提に、翻訳テーブルの構造を確認しました。実環境では、導入済みの言語パックやカスタマイズによって件数・言語分布・設定の数が変わります。