Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

静的解析で実現した効率的なi18n対応の仕組みづくり

minako-ph
November 23, 2024

 静的解析で実現した効率的なi18n対応の仕組みづくり

JSConf JP 2024 セッション資料

▼ 内容
・ESLintを静的解析に置き換えたら実行時間が5分の1に短縮された話
・静的解析を活用して、非エンジニアでもUIチェックを可能にした話
・i18nを導入しても開発効率を損なわない仕組みを構築した話
・業界用語を学習させたGPTベース機械翻訳をスプレッドシートに組み込んだ話

minako-ph

November 23, 2024
Tweet

More Decks by minako-ph

Other Decks in Technology

Transcript

  1. ⽬次 Agenda • ⾃⼰紹介と会社紹介 • ESLintを静的解析に置き換えたら実⾏時間が5 分の1に短縮された話 • 静的解析を活⽤して、⾮エンジニアでもUI チェックを可能にした話

    • i18nを導⼊しても開発効率を損なわない仕組み を構築した話 • 業界⽤語を学習させたGPTベース機械翻訳をス プレッドシートに組み込んだ話
  2. © LayerX Inc. 4 • 2023年8月 株式会社LayerX 入社 ◦ バクラク申請・経費精算

    ソフトウェアエンジニア • 型しか勝たん • ex - ◦ 株式会社メディカルフォース ▪ リードエンジニア ◦ DMM.comグループ 株式会社終活ねっと ▪ フロントエンドエンジニア 山本美奈子(minako-ph) 自己紹介
  3. © LayerX Inc.  5 会社概要 会社名 株式会社LayerX(レイヤーエックス) 代表取締役 代表取締役CEO 福島 良典

    代表取締役CTO 松本 勇気 創業 2018年 8⽉1⽇ 資本⾦ 約132.6億円 拠点 東京本社 〒104-0045 東京都中央区築地1-13-1 銀座松⽵スクエア 5階 関⻄⽀社 〒530-0003 ⼤阪市北区堂島1-1-5 関電不動産梅⽥新道ビル B2F WORKING SWITCH ELK 内 中部⽀社 〒466-0064 愛知県名古屋市昭和区鶴舞1-2-32 STATION Ai内 九州⽀社 〒810-0801 福岡県福岡市博多区中洲3-7-24 WeWorkゲイツ福岡 11F 内 従業員数 325名 (2024年5⽉末時点) 関連会社 三井物産デジタル‧アセットマネジメント株式会社 三井物産、LayerX、三井住友信託銀⾏、SMBC⽇興証券、JA三井リースによる合弁会社 株主⼀覧
  4. © LayerX Inc.  6 事業概要 「すべての経済活動を、デジタル化する。」をミッションに掲げ、 法⼈⽀出管理サービス「バクラク」や企業内業務のデジタル化を⽀援するサービスを提供しています。 バクラク事業 企業活動のインフラとなる 法⼈⽀出管理(BSM)SaaSを開発‧提供

    Fintech事業 ソフトウェアを駆使したアセットマネジ メント‧証券事業を合弁会社にて展開 AI・LLM事業 ⽂書処理を中⼼とした、LLMの活⽤による プロセスのリデザイン 取得認証 ※IS747702 / ISO27001 は三井物産デジタル‧アセット‧マネジメント事業部以外の組織で 認証取得
  5. © LayerX Inc.  7 「バクラク」シリーズラインナップ ‧AIが請求書を5秒でデータ化 ‧仕訳 / 振込データを⾃動作成 ‧電帳法‧インボイス制度にも対応

    仕訳‧⽀払処理効率化 ‧年会費無料で何枚でも発⾏可 ‧カード利⽤制限で統制を実現 ‧すべての決済で1%以上の還元 法⼈カードの発⾏‧管理 ‧帳票の⼀括作成も個別作成も⾃由⾃在 ‧帳票の作成‧稟議‧送付‧保存を⼀本化 ‧レイアウトや項⽬のカスタマイズも可能 請求書発⾏ ‧スキャナ保存データも直接取込  ‧AI-OCRが⾃動読取&データ化 ‧[取引先][取引⽇][取引⾦額]での検索 帳票保存‧ストレージ ‧AIが⾒積書‧請求書を5秒でデータ ‧スマホからも申請‧承認OK ‧柔軟な通知設定‧承認の催促機能 稟議‧⽀払申請 ‧直感的UIで従業員の負担を軽減 ‧Slack連携で打刻や⾃動リマインド可能 ‧わかりやすい残業 / 休暇管理レポート 勤怠管理 ‧AIが領収書を5秒でデータ化 ‧スマホアプリとSlack連携あり ‧領収書の重複申請などミス防⽌機能 経費精算
  6. © LayerX Inc. 9 ESLintを静的解析に置き換えたら実⾏時間が5分の1に短縮された話 • 要件 ◦ 特定ページに限定してi18n対応を⾏う •

    起こったこと ◦ 複雑な画⾯において、条件分岐や依存関係を網羅し全てのコードベースで漏れなくi18n対応を ⾏うことが難しかった ◦ 依存関係のあるコードベースにのみ翻訳漏れ検証を⾏う必要がある為、全コードベースを検証 する既存のESLintを適⽤できなかった • 対策 ◦ 指定されたページのVueコンポーネントファイル及びその依存関係にある「コンポーネント」 ‧「関数」‧「変数」を再帰的に分析し、翻訳関数によって囲まれていない⽇本語リソースを 特定するカスタムESLintの実装を⾏った i18n導⼊時に直⾯した課題と対策
  7. © LayerX Inc. 11 • 指定されたページから参照されるコードに限定して翻訳漏れがないことを検出するカスタムESLint ルールを実装する ◦ 翻訳漏れはt関数で囲われているかで検証 ◦

    参照されるコードはコンポーネント‧関数‧変数に限定して、再帰して末端まで検証 • i18n対応は指定されたページに限定したいので、翻訳すべきコードをページ起点で検索する カスタムESLintの要件 TSKaigi 2024 After Talk より
  8. © LayerX Inc. 15 【1】 vueファイルをASTに変換 a. template内のNodeを末端まで再帰して翻訳 漏れがないか検証 b. script内のNodeを末端まで再帰して翻訳漏

    れがないか検証 指定されたページから参照されるコードを再帰的に検索し、翻訳漏れを検知 TSKaigi 2024 After Talk より
  9. © LayerX Inc. 16 【2】 importがある場合の処理 a. vueファイルのimportがあれば、vueファイ ルの検証に再帰させる b. tsファイルのimportがあれば、そのtsファ

    イルをASTに変換し、importされている処 理を抽出してscriptの検証に再帰させる 指定されたページから参照されるコードを再帰的に検索し、翻訳漏れを検知 TSKaigi 2024 After Talk より
  10. © LayerX Inc. 18 以上がTSKaigi 2024 After Talkにてお話した内容になります。 • できたこと

    ◦ 翻訳漏れを機械的に検知できるようになった • 発⽣した問題 ◦ PR時にCIで翻訳漏れの検証を実⾏するように設定しましたが、処理時間が⻑く、開発者に負 担が発⽣。 ▪ Github Actions上 → 約10分 ▪ local環境 → 約5分 カスタムESLintを実装したその後 ESLintを静的解析に置き換えたら実⾏時間が5分の1に短縮された話
  11. © LayerX Inc. 19 • 重複解析の発⽣ ◦ ESLintは起点ファイルごとに解析を⾏うため、複数のファイルで共通のコンポーネントを参 照している場合、それぞれの起点ファイルから同じ依存ファイルが再解析されてしまう。 ◦

    プロジェクトが⼤規模になるほど依存ファイルの重複解析が増加し、実⾏時間が⼤幅に⻑く なる原因となっていた。 • 訪問済みファイルの管理限界 ◦ ESLintでは、起点ファイルごとにスクリプトが実⾏される為、独⽴した訪問済みファイルリ ストを使⽤しており、共通の依存ファイルでも各起点ファイルから個別に解析が⾏われる。 ◦ この仕組みにより、同じファイルが何度も解析され、全体の処理時間が増⼤する要因となっ ていた。 ESLintでの課題 ESLintを静的解析に置き換えたら実⾏時間が5分の1に短縮された話
  12. © LayerX Inc. 21 • ESLintは翻訳漏れ検出には不要なScope Analysisを実⾏するため、処理時間が増⼤していた。 • 静的解析スクリプトではScope Analysisを省略し、必要な処理にのみ集中することで効率化を実

    現。 • ESLintではテンプレートとスクリプトを別々に解析するため、静的解析スクリプトにより統合解析 が可能になり、効率的な解析が可能になりました。 ESLintの汎⽤性によるオーバーヘッド ESLintを静的解析に置き換えたら実⾏時間が5分の1に短縮された話
  13. © LayerX Inc. 22 • 時間短縮の成果 ◦ ESLint使⽤時:約255秒 → 静的解析スクリプト使⽤時:約54秒(約80%の時間短縮)

    ◦ 重複解析の解消と訪問済み管理のグローバル化により、⼤規模プロジェクトでも再解析を避 け、実⾏時間を⼤幅に削減しました。 • 開発体験の向上 ◦ CIやローカルでの検証が迅速化され、開発者がより早くフィードバックを得られる環境が整い ました。これにより、デプロイフローが改善され、開発者の負担が軽減しました。 実際の効果 ESLintを静的解析に置き換えたら実⾏時間が5分の1に短縮された話
  14. © LayerX Inc. 23 • データ管理の⼯夫によるパフォーマンス向上 ◦ 再帰的な解析では、訪問済みファイルの管理と重複排除の⼯夫が⾮常に⼤きな効果を発揮し ました。 ◦

    Scope Analysisなど省略することで、特定⽤途に不要な処理を削減し、静的解析を効率的に実 ⾏できました。 • ⽤途特化型スクリプトの強み ◦ 汎⽤的なツールよりも特化型スクリプトが特定解析に適しており、プロジェクトのニーズに合 わせた効率的な解析が可能となりました。 学びと応⽤ ESLintを静的解析に置き換えたら実⾏時間が5分の1に短縮された話
  15. © LayerX Inc. 25 • 翻訳情報の管理 ◦ スプレッドシートで管理し、社内外で翻訳を実施 • 発⽣した課題

    ◦ 翻訳情報が更新されたとき、どの画⾯に影響が出るかが不明 ◦ エンジニアが使⽤箇所をコードベースから検索する必要が発⽣ 翻訳情報の扱いと発⽣した課題 静的解析を活⽤して、⾮エンジニアでもUIチェックを可能にした話
  16. © LayerX Inc. 26 • 静的解析スクリプトの流⽤ ◦ 依存関係のあるコードベースの検証スクリプトを流⽤し、各翻訳キーの使⽤箇所を特定 • ⽬的

    ◦ 各キーがどの画⾯で使われているかを可視化し、影響範囲を即座に把握可能に 解決策の概要 静的解析を活⽤して、⾮エンジニアでもUIチェックを可能にした話
  17. © LayerX Inc. 27 1. 指定されたページから再帰的にコードを辿り、翻訳関数で使われるキー を検出 2. csvファイルに、キーに対して呼び出されている「コンポーネント」と 「⼤元のページパス」を保存

    3. スプレッドシートとの接続を担っているツールを介して、csvファイルの 内容をシートに転記 4. 翻訳辞書シートにキーで突合してページパスからURLを⽣成して表⽰ 全体のアーキテクチャ 静的解析を活⽤して、⾮エンジニアでもUIチェックを可能にした話
  18. © LayerX Inc. 28 • 詳細 ◦ 指定されたページから参照されるコードを、末端まで再帰的にアク セスし翻訳関数から呼び出されているキーを検出 ◦

    csvファイルに、キーに対して呼び出されている「コンポーネン ト」と「⼤元のページパス」を保存 • ⾒送った⼿法 ◦ 全てのソースコードを検証にかけて、検出されたキーから再帰的に ⼤元のページパスを辿る⽅法もあったがコスパ悪いので 前項で紹介 した 指定されたページに依存関係のある処理を検証するスクリプト のアルゴリズムを流⽤し ページ起点で検証を⾏った 指定されたページから再帰的にコードを辿りキーを検出 静的解析を活⽤して、⾮エンジニアでもUIチェックを可能にした話
  19. © LayerX Inc. 29 • スプレッドシートとの接続を担っているツールを介して、csvファイルの 内容をシートに転記 • この処理はベースブランチにマージが⾏われる度に Github

    Acrtionsから 実⾏しています csvファイルをスプレッドシートに転記 静的解析を活⽤して、⾮エンジニアでもUIチェックを可能にした話
  20. © LayerX Inc. 30 • csvから転記された情報と翻訳辞書をキーで突合してURLを⽣成して表⽰ • 各キーの使⽤箇所シート • 翻訳情報シート

    ページパスからURLを⽣成して表⽰ 静的解析を活⽤して、⾮エンジニアでもUIチェックを可能にした話
  21. © LayerX Inc. 35 再度TSKaigi 2024 After Talk へ登壇した際の資料より、この問題についてどのように解決したかお話しさ せてください。

    翻訳関数のキーに誤った値を指定できてしまう課題 i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  22. © LayerX Inc. 36 • @nuxt/i18nではt関数に翻訳情報のkeyを渡すことで国際化ができます • しかし... 存在しないキーを渡せてしまい、予測補完も効かないのでタイポを起こしやすい💦 •

    変数の渡し忘れや変数名の間違いなど、変数の過不⾜に気付けない😭 @nuxt/i18nに型を当てる前の状態 TSKaigi 2024 After Talk より
  23. © LayerX Inc. 37 • 私たちは翻訳作業をスプレッドシート上で⾮同期で進めていて、それをスクリプトでロードしなが らプロダクトに適⽤しています 1. スプレッドシートで定義されているkeyが、t関数のキーの型として当たること 2.

    スプレッドシートで定義されている翻訳情報に含まれる変数が、t関数の変数の型として当たること 3. 型が当たることにより予測補完が効き開発体験が保証されること 要件 TSKaigi 2024 After Talk より
  24. © LayerX Inc. 38 1. スプレッドシートから翻訳情報jsonを⽣成 2. 翻訳情報jsonからt関数に当てる型ファイルを⽣成 3. patchファイルで元のt関数の定義を削除

    4. ⽣成された型ファイルでt関数のキーと変数に型を当てる 全体のアーキテクチャ TSKaigi 2024 After Talk より
  25. © LayerX Inc. 40 • ts-nodeで実⾏可能なmtsファイルにスクリプトを⽤意し以下 のようなMessagesインターフェースの型を作成 ◦ 翻訳情報にアクセスするキーをMessagesのキーに ◦

    翻訳情報の中で変数プレースホルダが使⽤されていれば paramsに変数として抽出 翻訳情報jsonからt関数に当てる型ファイルを⽣成 TSKaigi 2024 After Talk より
  26. © LayerX Inc. 41 • TypeScriptでは、ライブラリの型定義に何かを追加はできても削除はできず、t関数を真に型安全に することが難しかったです • そのためpnpmに搭載されているpatchコマンドを使⽤してパッチを当てることで対応しました ◦

    t関数に関する型定義のコメントアウトを⾏いました ◦ pnpm patchはパッケージのコードに対するローカルな変更を容易に⾏える機能です(便 利!) patchファイルで元のt関数の定義を削除 TSKaigi 2024 After Talk より
  27. © LayerX Inc. 45 i18nを複数⼈で運⽤するにあたり、ルールが存在していても、実装時に思い出す⼿間や、気づかずに異な る実装をしてしまう可能性がありました。 • Vueには複数のAPIスタイルがあり、翻訳関数の呼び出し⽅法が実装者によってばらつく。 • 記号を含む⽂⾔のキーの切り出し⽅が、実装者によって異なってしまう。

    • 翻訳情報にHTMLタグを含む場合、パース処理を忘れてしまうリスクがある。 そこで、これらの課題に対してカスタムESLintを導⼊し、実装者が意識せずとも機械的にルールが適⽤さ れる仕組みを整備しました。 実装者によるばらつきの発⽣ i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  28. © LayerX Inc. 46 • 環境 ◦ Vue.js ▪ OptionsAPIとCompositionAPIとScriptSetupが混在している

    ◦ @nuxt/i18n ▪ 呼び出せる関数は t() と $t() • ルール ◦ OptionsAPIでは $t() を使⽤すること ◦ CompositionAPIとScriptSetupでは t() を使⽤すること 翻訳関数のばらつきを防ぐルールの実装 i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  29. © LayerX Inc. 47 • templateタグ内に対する検証 ◦ <script setup>を使っている場合、テンプレート内では"t"関数の使⽤を期待 ◦

    <script setup>を使っていない場合(Options APIやComposition APIのsetup関数外)、テン プレート内では"$t"関数の使⽤を期待 ◦ 指定された関数と異なる関数が使⽤されている場合、エラーとして報告 • scriptタグ内に対する検証 ◦ <script setup>内であれば"t"関数の使⽤を期待 ◦ Composition APIのsetup関数内でも、同様に"t"関数の使⽤を期待 ◦ それ以外の場所では、"$t"関数の使⽤を期待します。 ◦ 間違った関数が使⽤されている場合、エラーとして報告 翻訳関数のばらつきを防ぐルールの実装 i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  30. © LayerX Inc. 49 • ()で囲まれている⽂⾔ • :で終わる⽂⾔ • ‧で始まる⽂⾔

    上記のようなパターンでi18nのキーに記号が含まれる場合、⽂⾔の⼆重管理を防ぐために記号をキーに含 めない⽅針としました。しかし、このルールを実装者が毎回意識するのは難しいため、カスタムESLintで ⾃動的にルールが適⽤される仕組みを整備しました。 記号の⼀貫した取扱いルールの実装 i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  31. © LayerX Inc. 50 • キーが先頭に「‧」を含む場合の検証 ◦ i18nキーが「‧」で始まる場合、そのキーの⻑さが1⽂字以上であればエラーとして報告 ◦ メッセージとして「「‧」は単独のキーとして使⽤してください」というエラーメッセージを表⽰

    • キーが末尾に「:」を含む場合の検証 ◦ i18nキーが「:」で終わる場合、そのキーの⻑さが1⽂字以上であればエラーとして報告 ◦ メッセージとして「「:」は単独のキーとして使⽤してください」というエラーメッセージを表⽰ • キーが「(」で始まり「)」で終わる場合の検証 ◦ i18nキーが「(」で始まり「)」で終わり、かつ2⽂字以上である場合、エラーとして報告 ◦ メッセージとして「「(」と「)」は単独のキーとして使⽤してください」というエラーメッセージを表⽰ 記号の⼀貫した取扱いルールの実装 i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  32. © LayerX Inc. 51 翻訳キーにHTMLタグが含まれる場合、不適切なサニタイズが⾏われていないと、セキュリティリスクや 表⽰崩れの原因となります。これを防ぐため、以下のルールを定めました。 • HTMLタグを含む翻訳キーには、必ず$sanitizeでサニタイズする • サニタイズ済みの翻訳キーは、v-htmlとともに使⽤する

    このルールを⼿動で覚えるのは困難なため、カスタムESLintルールで⾃動チェックを⾏い、機械的にルー ルを守れるようにしました。 HTMLタグを含む翻訳キーの安全性検証の実装 i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  33. © LayerX Inc. 52 • キーの取得と検証 ◦ t関数が呼ばれている場合、その最初の引数がリテラル⽂字列(翻訳キー)であるかを確認 ◦ 翻訳キーがリテラル⽂字列であれば、そのキーを使って対応する翻訳値(⽂字列)をi18n

    ファイルから取得 • HTMLタグの存在確認 ◦ 翻訳値の⽂字列にHTMLタグが含まれているかを判定します。具体的には、正規表現を⽤い て、<や>で囲まれたタグ形式の⽂字列が存在するかをチェック ◦ もしHTMLタグが含まれている場合、その翻訳値にはHTMLが含まれていると判断され、サニ タイズとv-htmlチェックを⾏う HTMLタグを含む翻訳キーの安全性検証の実装 i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  34. © LayerX Inc. 53 • PR作成時 ◦ i18n-check-untranslated ▪ 翻訳漏れがないか検証します

    ◦ analyze-i18n-keys ▪ 各キーに対する使⽤箇所に変更があるかチェックします ◦ (ESLint, TypeCheck) ▪ 存在しないキーを呼び出していないか検証します ▪ 適切なt関数を使⽤しているか検証します ▪ 記号を含むキーを適切に定義できているか検証します ▪ 翻訳情報にHTMLタグを含むキーが適切に処理されているか検証します これまで登場した仕組みのCIへの導⼊ i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  35. © LayerX Inc. 54 • developへpush時 ◦ check-and-put-i18n-keys ▪ 各キーに対する使⽤箇所に更新があればスプレッドシートに反映します

    これまで登場した仕組みのCIへの導⼊ i18nを導⼊しても開発効率を損なわない仕組みを構築した話
  36. © LayerX Inc. 56 先ほどのお話の中で 翻訳を社内外で実施しているというお話をさせていただきました。 しかし、開発現場では以下のような課題がありました。 • 実装を開始する前に翻訳の依頼を出し、その対応を待つ必要があるため、開発スピードが低下して しまう。

    • ドメイン特有の⽤語が多く、⼀般的な翻訳サービスでは⼗分に対応できない。 翻訳依頼フローの課題とドメイン⽤語対応の必要性 業界⽤語を学習させたGPTベース機械翻訳をスプレッドシートに組み込んだ話
  37. © LayerX Inc. 58 1. ローカル環境でTypeScriptを使⽤して翻訳スクリプトを実装。業 界⽤語は実⾏時にスプレッドシートから読み込み 2. Babelを⽤いてJavaScriptに変換 3.

    Claspを使⽤しGASへデプロイ 4. スプレッドシートから機械翻訳処理の呼び出し 5. 翻訳結果をスプレッドシートへ書き込み 全体のアーキテクチャ 業界⽤語を学習させたGPTベース機械翻訳をスプレッドシートに組み込んだ話
  38. © LayerX Inc. 59 • TypeScriptを⽤いてGPTのAPIを呼び出すスクリプトを実装 • ドメインに特化した⽤語とそれに対する翻訳は実⾏時にスプレッ ドシートから読み込み、辞書としてプロンプトに提供 •

    作成された辞書を⽤いて翻訳を実装するよう指⽰ GPTを⽤いた機械翻訳の仕組みを実装 業界⽤語を学習させたGPTベース機械翻訳をスプレッドシートに組み込んだ話
  39. © LayerX Inc. 60 • Babelを⽤いてTypeScriptを実⾏可能なJavaScriptに変換 • Claspを⽤いてGAS( Google Apps

    Script )にデプロイ • Clasp( Command Line Apps Script )とは ◦ Claspは、GAS プロジェクトをローカル環境で管理し、コー ドを同期‧デプロイするためのCLIツールです ◦ ローカルで作成‧管理したコードをGAS にデプロイして実⾏ 可能な状態に ◦ GASのスクリプト管理やバージョン管理を効率化 GASへのデプロイ 業界⽤語を学習させたGPTベース機械翻訳をスプレッドシートに組み込んだ話
  40. © LayerX Inc. 66 We are hiring! LayerX Open Door

    アカウント登録が一切不要なカジュアル面談を公開しています。 ・私と雑談してみたい ・質問したいことがある ・選考に進むか悩んでいる などなど、お気軽にお申し込みください。 公開中の募集ポジションをはじめ、LayerXの各事業部の紹介、社員イ ンタビュー、Podcastなどのリンク集をまとめています。 コンテンツも充実しているので転職タイミングじゃなくてもWebサイト に訪問いただけると嬉しいです! LayerX 採用情報 LayerX 採用情報