ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
各言語に対応したテキストの簡素化
App内のテキストをローカライズすると、世界各国のユーザがそのAppを利用しやすくなります。文字列の正確な書き方やフォーマットなど、ローカリゼーションのワークフローを構築するためのベストプラクティスを紹介し、Xcodeを使って異なる言語のローカリゼーション用に文字列を準備する方法を確認しましょう。
リソース
関連ビデオ
WWDC22
WWDC21
WWDC20
WWDC19
-
ダウンロード
♪ (各言語に対応した テキストの合理化) こんにちはWWDCへようこそ Appleのlocalizationチーム のトーマスです そして今日はローカライズされた 文字列を 合理化する方法をお見せします 多くの言語でAppを機能させる 最も簡単な方法について解説します まずUIコードを記述します 次にターゲット内の文字列を 整理する方法を説明します その後 Xcodeに 手間のかかる作業を任せます 最後に高度な文字列の 新しいテクニックを学びます これで私たちはあなたの Appが素晴らしい翻訳の 準備がされていると保証します テキストは私たちの生活の いたるところにあり非常に重要です テキストを使用して会話し 現実の世界で情報を入手します それは明らかに私たちの 接続されたデバイスの すべてのApp 通知 そして 私たちが毎日読む記事に さらに当てはまります これまで以上に正確で アクセスしやすいテキストを 読むことができることが重要です この通りですっかり迷子になり すべての看板の中から 小さな店を見つけようとしていると 想像してみてください Appのユーザーも 同じである可能性があります テキストはそのようなコア機能です それはユーザーを導き 親しみやすさをもたらします このようにAppを ローカライズすることは 特にApp Storeが 提供するすべての市場で 世界中のすべてのユーザーに 手を差し伸べる良い機会です 開発者としてあなたはすでに テキストに精通しています 私たち開発者は物事に名前を 付けるのを楽しんでいるので テキストを「文字列」と呼びました 文字列はいたるところにあります: タイトル ボタン ユーザーコンテンツ オンラインコンテンツ 検索クエリ グラフィック アクセシビリティラベル 等です App内のすべての文字列を 映画の字幕と考えてください あなたが見ている映画では 適切な言語で適切なタイミングで 適切なコンテキストで 全編を通して すべての字幕が必要です これはここでもまったく同じです あなたの文字列はユーザーがApp における通りをナビゲートできるように あなたの視覚的コンテンツに 意味を伝えます 開発者の観点から ローカリゼーションプロセスとは 何かを見てみましょう ユーザーインターフェイスは ビューに文字列を表示します それらの文字列は 独自のファイルに存在します これにより すべての言語に 共通するビジュアルコンテンツと 個別の翻訳とを分けて 考えることができます その間にFoundation フレームワークと ユーザーインターフェイスと すべての文字列をリンクします このセッションではこれらの 各コンポーネントについて 詳細を説明します それはたくさんのように見えます しかし私たちはすべてを 段階的に明らかにします ユーザーインターフェイス文字列を 定義することから始めましょう 最新のAppleテクノロジーの 組み合わせで ローカライズされた 文字列の表示は簡単です Appでこれらのテクニックを 使用することをお勧めします ローカリゼーションについて 二度と考える必要がないように! UIで定義する文字列はすべて ローカライズする必要があります 表示される文字列には 2つのタイプがあります 1つはビューを作成するときに 直接定義されます ここではSwiftUIとStoryboardで ラベルを定義しました はい!どちらも ローカライズ可能です 簡単だと言いいましたよ! 2番目のタイプの文字列は より一般的で SwiftUIのモデルコード AppKitやUIKitでも 見つけることができます 文字列を変数に格納したり または関数から返したりする 必要があるかもしれません これらすべての場合で NSLocalizedStringを使用できます iOS 15とmacOS Montereyの 新機能で Swiftの洗練されたメソッド String(localized :)を使用できます SwiftUIの最初の方法に 少し焦点を当てましょう インターフェイスに表示するものは すべて実際にはビューです これがテキストラベルかボタンか デフォルトではすべて ローカライズ可能ですが 将来の翻訳された文字列を ホストする準備ができました これはデフォルトで 有効になっているため プレビューなどの モックコンテンツがある場合は 逐語的に使用しオプトアウト するようにしてください これにより翻訳者の 不要な作業を回避できます この関連セッションではより多くの テクニックを学ぶことができます 基本には言及したので この文字列をより動的にする 方法を学びましょう 現在ローカライズされたボタンを 注文するために表示しています 私がコンサートを愛している ことを知らないかもしれません アーティストが友達と一緒にいる のをもっと見るのが好きです! このAppでは私はすべての 友達のために注文している チケットの数は 明らかではありません それでは選択したチケットの 数を含めるため そのボタンを改善しましょう 簡単でした 私がSwiftで慣れているように 文字列に変数を挿入しました ここではカウントは 実行時に 実際の数3に置き換えられます 今私たちが見てきた すべのオプションの (format :)の文字列の よくある落とし穴を 指摘したいと思います (format :)の文字列は 素晴らしいですが ローカライズされた文字列に 使用するためのものではありません アラビア語の例で 理由を見てみましょう ここでテキストの方向と数字は 異なる場合があります 良いニュースとしては String(localized :)を使用する場合 両方とも自動的に管理されます ボタンに今数字「3」は アラビア語で のユーザーの 希望する数字に応じて 正しく書かれています String(localized :)は 複数形もサポートし 文字列の各部分の分離 つまり双方向テキストでは 単語がシャッフルされません 最後に変数を使いすぎないように 注意してください 文字列を接着するのは便利ですが 翻訳の問題につながる 可能性があります ここで"オーダー"という言葉は 今注文するのか後で注文するのか ある言語では異なる 書き方をします 2つの別々の文字列を 使用する方が安全です いいでしょう 私たちが見るべき 1つの主要な最後の側面があります それは私が今まで密かに あなたから遠ざけていたことです 定義した文字列を あなた以外の誰かによって 翻訳する必要があります 文字列ごとに翻訳している間 翻訳者の前に 完全なApp UIはないのに それらはすべての文字列で 一貫性を保つ必要があります なので コードコメントを 追加することで 同僚があなたのコードを 理解するのを助けるのと同じように 助けが必要なのです 文字列に関係なく 常にコメントを定義する 必要があると私は主張します またStoryboardファイルでも 忘れないでください IDインスペクタに コメントフィールドがあります 翻訳者を支援するための ヒントをいくつか紹介します まずコメントで文字列が表示される 場所を説明する必要があります たとえば これはボタン?ラベル? いくつかのVoiceOverテキスト? これがアクションであるか どうかを知る-注文する- または ステートメント (注文)が重要です 第二に文脈を 説明する必要があります 注文を押すと取引は完了しますか またはリストを並べ替えますか? 最後にコメントは変数を 説明する必要があります 翻訳者があなたの 文字列を見るとき 彼らはあなたのコードを見ないので 手がかりを得るための 変数の名前でなく 代わりに一般的な プレースホルダーのみ表示されます したがってここでの最後の例では 「Ordered」の前の数字は 何を表していますか? これは過去の注文数ですか? 注文したばかりのチケットの数? はい!コメントのおかげで チケットの総数だとわかります 多くの言語の翻訳者が 「チケット」という言葉の ジェンダーにより 正しく翻訳できるようになります 場合によってはコメント内の 変数の値の例を書くのが 最も簡単なこともあります それを念頭に置くと こうなります UIコードをローカライズする 準備ができました 次に文字列とは別に UIコードを維持する方法を 学習します 基本的にあなたはあなたの 文字列が存在する場所を 整理することができるでしょう これを行うために Foundationがどのように コードが正しくローカライズされた 文字列ファイルを 確実に読み込むのかを 見てゆきましょう もちろんローカリゼーションは 言語から始まります プロジェクト設定に移動して 新しい設定を追加できます Xcodeを見てみましょう プロジェクトを選択し プラスボタンをクリックします ローカリゼーションを追加します 最新バージョンでメニューに たくさんの新しい言語が 得られているのが分かるでしょう 見てみましょう... ローカリゼーションAppリストは トップのベースから始まります 確かにこれはUI要素が 存在する場所で 言語間で共有されているからです たとえばStoryboardファイルは 有されます Siri Intentsファイルも 共有されます 次にそれらをベースに 追加する必要があります なので すべての共有資産に対して 必ずボタンを クリックしてください それでOKですがその一方で あなたの文字列は 共有されません 文字列は1つの言語に属しています だからあなたは英語での文字列と アラビア語のすべての 文字列があるでしょう 特定の言語の文字列を使用して Appをテストするには SwiftUIでプレビュー 環境を変更 またはAppスキームの 設定を変更します デバイスがAppでサポート されていない言語である場合 Foundationは最良の 代替案を見つけようとします 私の電話がメキシコの スペイン語の場合 Foundationは ラテンアメリカスペイン語に それからスペイン語に 次にApp開発言語たとえば英語に フォールバックしようとします 最後に文字列 がサーバーから来る場合 ユーザーの好みの言語を 尊重するようにしてください 素晴らしい 各言語には文字列のコレクションが あることがわかりました これらの文字列はさらに 「テーブル」と呼ばれる ファイルに整理できます すべての文字列を 好きなように整理するため この機能を使用できます たとえば各機能または 各画面のテーブルを 作成できます これはデフォルトでは オプションなので すべての文字列はLocalizableという 名前のテーブルに配置されます 具体的にはこれはすべての文字列 Localizable.stringsという名前の ファイル内に格納されることを 意味します これまでに学んだことを要約し 例を見てみましょう 私は変数を使用して文字列を宣言し カスタマイズされたテーブル名と コメントのある次のコードを 持っています 私のAppがフランス語を サポートしているとしましょう Xcodeでは英語からの フランス語の翻訳が含まれている UserProfile.strings ファイルが必要になります フランス語のリソースフォルダに 保存されます 慣例によりfr.lprojという 名前が付けられています コメントはフランス語の翻訳者に とって非常に役に立ちました 「places」という女性名詞をマーク するために「e」を使用しました ticketsのフランス語は 女性名詞です 少しスパイスを効かせて バンドルについて話しましょう このパラメータによりターゲット をまたいで文字列をロードできます バンドルパラメータは デフォルトでmainです あなた自身のAppでは それを必要としません mainはそのAppです App Extensionでは mainは独自のExtensionを 指します だからそれを 必要としないのです しかしAppとそのExtensionの間で 文字列を共有したいとしましょう Extensionではあなたは メインAppのバンドルを 提供する必要があります そうすることで2つの間で文字列が 重複するのを防ぐことができます フレームワークから文字列を 取得することもできます その場合 フレームワークの文字列を 直接利用するか App内のコードでバンドルを 指定することで またはフレームワークが直接 使用できる変数を提供します これらのローカライズされた文字列 変数がフレームワークで フレームワーク自体のバンドルを 指定することで定義されています モデルを振り返ってみましょう 今だけ私達は私達のAppを フレームワークによって提供される文字列を ロードさせるために それを更新します フレームワークは文字列を定義し 文字列ファイル内の独自の バンドル内に翻訳が 保存されていることを Foundationに通知します このパラメータがないと代わりに ホスティングAppから 文字列がフェッチされ 見つかりません 実際には このように見えます テキストが保存されている バンドルを提供します フレームワークは独自のバンドル内の 文字列を探します そうすればAppにとっては 簡単です 文字列は単純な コード行で使用できます さらにローカリゼーションを 実装する場合 このようにフレームワークで 作成する必要はありません ここに示されている文字列 ファイルにはcompleteが含まれています 理由を見てみましょう コードでできることは すべて見てきました 文字列を宣言して整理します しかし実際にあなたの 翻訳を保持する ファイルを作成する 方法は見ていません 実際にそれらの文字列 ファイルを作成する 必要はないことがわかりました Xcodeはすべての .stringsファイル 作成を処理できます エクスポートローカリゼーションを 使用する場合 コードを読み取りすべての 文字列を抽出します 文字列ファイルを維持する必要が ないのでこれは素晴らしいことです 文字列のローカライズを 忘れていた場合 UIでコーディングしたばかりですが これはあなたのためです genstringsに 苦労している場合は これもあなたのためです 今年Xcode 13で Swift文字列抽出のコンパイラ サポートを追加しました またワークスペースが完全に サポートされるようになりました これによりロジックと あなたの翻訳間の 懸念がさらに分離されます XcodeはSwiftから テキストと以前に見た Foundationメソッドを 検出して抽出します カスタムコードを お持ちの場合はご注意ください これらのAPIをラップしますが これはデフォルトでは機能しません 通常 メソッドやマクロを 使用する必要はありません しかし本当に必要な場合は それらを文字列マクロ名の下 ビルド設定に 追加できます 残りは XcodeはApp名を ローカライズするために Info.plistで定義されている プライバシーの説明と 一般にローカライズ済みとして マークされたすべてのアセット Xcodeのインスペクタで 抽出します 既存のローカリゼーションが ある場合は すでに新しいUI用Xcodeの エクスポートに 移行できます 新しい文字列は既存のファイルに 自動的に追加されます これは自分のペースで プロジェクトを 変換したい場合に最適です ボーナスとしてUIテストの スクリーンショットが含まれました 翻訳者に最適です 文字列があるコンテキストを 取得するために App StoreでのAppのローカライズ されたスクリーンショットを 紹介するのは素晴らしいことです Xcodeは全ローカリゼーション カタログを抽出したので 今は翻訳者の番だと思うでしょう 実際あなたもそれを 行うことができます! Xcode 13の新機能エクスポート されたローカリゼーションカタログ これをXcodeで直接表示 および編集できます 生成された各ファイルを 確認できます 各テーブルは 左側のバンドルに 含まれています そしてあなたの選択のために 含まれているすべての文字列 画像 ファイルを確認できます 文字列のフィルタリング 並べ替え コメントの表示 スクリーンショットさらには翻訳! 独自のAppを開発して 翻訳する場合これはとても便利です 文字列を自分で確認して バグ修正することもできます 翻訳者が翻訳された 文字列カタログを返すと それらをXcodeの Productメニューを使い プロジェクトにインポートできます そしてどーん!あなたの 文字列ファイルstringsdicts およびその他のアセットが 作成および更新されます 同等のコマンドラインを使用して 自動化されたエクスポートと インポートを 継続的インテグレーション システムで実行できます 定期的に呼び出すことで プロジェクトは最新の文字列と 新しいUIを翻訳する際の 迅速なターンアラウンドを 取得します 強化されたワークフローの動作を 今年のセッション 「SwiftUI Appの ローカライズ」で確認できます こちらのセッションで詳細を ご覧ください それでおしまいです! あなたは文字列がどのように生まれ App内で生きているかを見ました 結論として より複雑な文字列を処理する 方法を紹介します そして私たちが用意している 新機能をきっと気に入るはずです 素晴らしいものから始めましょう! ローカリゼーションが 組み込まれている 属性付き文字列を改善しました Markdown構文のサポートにより 可能になりました! 文字列をフォーマットを 失うことなく ローカライズ できるようになったのです 1つの単語を太字にするためだけに 危険な文字操作をする 必要はありません そういえば完全性に 重点を置くため ここではアスタリスクを 使用しています リンク 強調 等幅テキスト等々を 追加する方法を学ぶには 「Foundationの新機能」を 確認することを お勧めします 文字列ファイルに1つの 翻訳があるコードで 定義する1つの文字列を 見てきました しかし時々あなたは複数の 表現を持つ文字列を必要とします これは定義したルールに適応する 文字列のコレクションである stringsdictファイルで可能です たとえば例を思い出してください どこでチケットを 注文したいですか? 英語では複数のチケットがあり 1つのチケットに「s」がない場合 接尾辞として「s」を追加します コードをシンプルかつ 正確に保つために stringsdictを使用してこの複数形を 定義する必要があります Appをローカライズすると これらのルールは言語ごとに 異なります ロシア語のいくつかの ケースを見てください あなたはそれをコードで 扱いたくない それはむしろローカリゼーションで 扱う必要があります それをどのように 実装するか見てみましょう コードを変更する必要はなく 上記の既存のコードを 引き続き使用します まずあなたのために作成されている 文字列ファイルと比較して stringsdictは手動オプトインです よってXcodeテンプレートを 使用して作成します インスペクタでの クリックを確認してください 大丈夫 それはすべて 文字列で始まります コードで定義しています あなたはコード内の複数の文字列を 複合してもってもっている場合は それぞれをこのルートエントリを ここに追加できます 内部では提示される 実際の値を定義します この値は検索置換 メカニズムに従います この例では 「チケット」という名前の トークンを1つ定義しました それは完全な最終文字列を 保持します トークンの中にテキストの ほとんどを入れるのがベストですが 翻訳者が接頭辞や接尾辞を付けたり 複数の変数がありにトークンを 移動させたりする 必要がある場合には そのフィールドは ローカライズされます OK そのトークンはコード内の 1つの変数に応じて異なります 次にそのチケットトークンを 定義しましょう まず複数化を行っていることを 確認します 次にCスタイルのフォーマッタ dで 変数が数値であることを示します 最後に複数のルールを 書くことができます 英語ではルールを「1つ」と 「その他」必要に応じて 「ゼロ」と宣言するだけです エントリごとに チケットトークンの実際の 値を書き込みます 次に チケットが3つある場合 英語では「その他」を使用します %dを数値3に置き換え 「3チケットの注文」を生成します 言語が多くのケースを必要とする 場合でも心配しないでください Xcodeはエクスポート時に それらを追加します ロシア語では既存のものの上に 少数と多くを追加します それでおしまいです! 文字列は実行時に複数化されます 先に進む前に1つのケースを 指摘したいと思います stringdictは複数形に 使用する必要がありますが 数字を含む文字列を 対象としています 英語の単数形の「1つ」の ケースは以前に見ました それは確かにロシア語でも 数字の1です ただし21 や31などにも 使用されます その場合stringsdictの 使用は正しくありません この例であなたが 望むのは1つだけに 等しく これや両方またはすべてによって 複数形は異なります 数字はありませんstringsdictは 使用しないでください 友達全員に21枚のチケットを 予約すると想像してみてください ロシア語で「すべてのチケットを 注文する」の代わりに 「このチケットを注文する」と 表示されます 「私のお金はどこ?」と 聞きたくなります 3つの文字列のそれぞれを 正しく複数形にするために 代わりにすべての言語でシンプル だが効果的なif / elseを 使用してください それが複数形のサポートですが stringsdictは多くのバリアント タイプ文字列を処理します 詳細については関連する セッションをご覧ください これは素晴らしいですが もっと簡単な方法を提供したい Foundationは今年 文法を学ぶ方法を学びました! 属性付き文字列に Markdownサポートが追加され この新しい形式を inflect属性で使用し このボタンのように 実行時に計算された 正しい値を取得します これはiOS 15とmacOS Montereyに 追加された素晴らしい新機能で 現在一部の言語で ご利用いただけます より詳細な制御が必要な場合は stringsdictを使用できます 複数形のサポートを追加する だけではありません ソフトウェア文字列をより 包括的にしたかったのです たとえばAppがユーザーを 歓迎する場合 英語ではかなり簡単です しかしそれはスペイン語では そうは行かず それはユーザーのアドレスの 用語に依存するからです これまでパーソナライズしていない 文字列の提示の必要がありましたが 正しいですがほとんどのスペイン語 ユーザーには堅苦しい 文字通り「私たちはあなたに 私たちの歓迎を与えます」です 文字列をユーザー向け パーソナライズできるならどうです 新しいMarkdown表記で 今それをすることができます! 文字列はデバイスの言語設定で 選択した アドレスの用語に従います だからユーザーのための 「bienvenida」 フェミニンで紹介されたい人 男性的な「bienvenido」 そして私たちが知らなければ 既存の語尾変化の 代替案を使用します 複数形およびアドレス起源の インライン語尾変化が コードまたはあなたの翻訳で 定義できます この新しい言語を選択の追加に 非常に興奮しています 私たちはあなたのAppが使うのを 見るのが待ちきれません 最後に今日はすべての 方法を見てきました ローカライズ可能な 文字列を書くことができます しかしデータを提示したい場合は あなたは実際にフレームワークsに それらを書くべきです 私たちのフォーマッターは 何百もの言語と地域そして さまざまな種類と単位の 組み合わせを処理します だからハードコーディングしないで 難しいことは任せてください そしてこれはSwiftで フォーマッタを採用し 今年からこれまで以上に 簡単になります 文字列の差し込みをインラインし 使いやすくしました 新しいお気に入りのAPIを 見つけるため今年の 「Foundationの新機能」 を確認してください 今日見たものすべての詳細を 入手してください 以前のリリースを展開する 必要がある場合や フォーマッタの詳細が必要な場合は 昨年のセッションの確認を いいでしょう今日 あなたに持って行ってほしいのは 最新のAPIを使用して コードを作成する場合 Xcodeはすべての文字列を 生成することです バンドル間で文字列を 整理する方法を見ました 文法とフォーマット作成のための あなたにとって簡単な 新しいAPIを発見しました これらすべてのテクニックに従うと 新しい言語を追加するのに コード変更の必要はありません! 最後に 常にテストします どんなに努力しても 文字列をローカライズするには Appをテストする必要があります すべての言語で正常に 動作することを確認します 完全にローカライズされたAppで コンサートを 予約がするのが待ちきれません WWDCの残りをお楽しみください ご覧いただきありがとうございます ♪
-
-
3:30 - Declaring a string
Button("Order")
-
3:44 - Declaring a string anywhere else
button.title = NSLocalizedString("Order", comment: "…") button.title = String(localized: "Order")
-
4:20 - Declaring a string in a SwiftUI view 2
Text("Your order is ready.") Button("Order") { // Action… }
-
4:33 - Declare a string in SwiftUI view with verbatim
Text(verbatim: "Sample data")
-
4:54 - Button to place an order
// SwiftUI Button("Order") { … } // Swift button.title = String(localized: "Order")
-
5:15 - Button to place an order with a variable
let count = 3 // SwiftUI Button("Order \(count) Tickets") { … } // Swift button.title = String(localized: "Order \(count) Tickets")
-
5:36 - Button to place an order with a variable 2
let count = 3 // Supports user’s preferred numbers, // pluralization, RTL variables isolation… // Previously: .localizedStringWithFormat() String(localized: "Order \(count) Tickets")
-
6:21 - Use 2 separate strings
// Recommended for all languages String(localized: "Order Now") String(localized: "Order Later")
-
6:57 - Button to place an order 2
// SwiftUI Text("Order") // Swift String(localized: "Order")
-
7:09 - Button to place an order with comment
// SwiftUI Text("Order", comment: "Button: confirms concert tickets booking”) // Swift String(localized: "Order", comment: "Button: confirms concert tickets booking")
-
7:36 - What makes a good comment
Text("Order", comment: "Button: confirms concert tickets booking") Text("Order", comment: "Button: confirms concert tickets booking") Text("\(ticketCount) Ordered", comment: "Order summary: total number of tickets ordered")
-
10:52 - Request server strings in the user's language
Bundle.preferredLocalizations(from: allServerLanguages).first
-
11:37 - Declare a string with a variable, customized table name, and a comment
Text("\(ticketCount) Ordered", tableName: "UserProfile", comment: "Profile subtitle: total number of tickets ordered")
-
13:49 - Using a framework
/* —-----------—------------—-—---- In TicketKit Framework —---------—------------—-—---- */ // TicketKit/OrderStatus.swift public enum OrderStatus { case pending, processing, complete, canceled, invalid(Error) var displayName: String { switch self { case .complete: return String(localized: "Complete", bundle: Bundle(for: AnyClassInTicketKit.self), comment: "Standalone ticket status: order finalized") /* —-----------—-----------—---—--- In Host App —---------—------------—-—---- */ import TicketKit Text(OrderStatus.complete.displayName)
-
17:43 - Import translated strings catalogs
xcodebuild -exportLocalizations -workspace VacationPlanet.xcworkspace -localizationPath ~/Documents xcodebuild -importLocalizations -workspace VacationPlanet.xcworkspace -localizationPath ~/Documents/de.xcloc
-
18:28 - Localized attributed strings
AttributedString(localized: "Your order is **complete**!", comment: "Ticket order confirmation title")
-
19:22 - Plural with stringsdict
String(localized: "Order \(ticketCount) Ticket(s)")
-
22:46 - Plural for strings without a number
if ticketCount == 1 { button.text = String(localized: "Order This Ticket") } else if ticketCount == 2 { // If needed button.text = String(localized: "Order Both Tickets") } else { button.text = String(localized: "Order All Tickets") }
-
23:31 - Automatic grammar agreement
AttributedString(localized: "Order ^[\(ticketsCount) Ticket](inflect: true)")
-
25:45 - Format data in strings
["pop", "rock", "electronic"].formatted(.list(type: .or)) // pop, rock, or electronic Text("Total: \(price, format: .currency(code: "USD"))", // Total: $9.41 comment: "Order subtitle: total price of all tickets")
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。