Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
実行場所を意識させない i18n API を作った話
Search
ANDPAD inc
August 21, 2026
Programming
23
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
実行場所を意識させない i18n API を作った話
柿森 隆生
2026 年 8 月 21 日
React Tokyo ミートアップ #19
ANDPAD inc
August 21, 2026
More Decks by ANDPAD inc
See All by ANDPAD inc
Go 1.27 における memory allocation の高速化
andpad
0
270
言語を使う側から、作る側へ。 自作 Lisp で得た新たな気づき。
andpad
0
160
OS アップデート対応の取り組み方がもっと共有されてほしい
andpad
0
130
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
490
ANDPAD Ruby sponsor session in RubyKaigi 2026
andpad
0
250
AWS WAFの運用を地道に改善し、自社で運用可能にするプラクティス
andpad
2
1.2k
アプリから 360 度カメラ「RICOH THETA」に接続して写真を撮影する
andpad
0
79
アンドパッドが提供する Drinks and Local Meals と Drinkup を大公開
andpad
0
140
建設DXを支えるANDPAD: 2025年のセキュリティの取り組みと卒業したいセキュリティ
andpad
0
570
Other Decks in Programming
See All in Programming
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
1.1k
運用ダッシュボードの設計を誰も教えてくれないのだけどみなさんどうしてるんですか? - チームに監視するという文化を根付かせるための第一歩を踏みたい -
satoshi256kbyte
1
130
【デモ】Kiroで体験する仕様駆動開発|設計からコーディングまでAIと進める開発フロー
cmkudo
0
230
FDEが実現するAI駆動経営の現在地
gonta
2
290
React本体のコードリーディング
high_g_engineer
1
150
php-fpmのプロセスが枯渇した日-調査・対処・そして本当にやるべきだったこと-
shibuchaaaan
0
330
Android CLI
fornewid
0
230
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
19k
Webエンジニアなのにブラウザの仕組みがわからないので、Pythonで自作してみた
tatsuki12
1
240
引き算の組織 ― アウトカムとAIに全振りするために辞めたこと ― / Organization by Subtraction
hirokiyamamoto14
PRO
0
260
Built Our Own Background Agent at LayerX
layerx
PRO
10
5.8k
いまどきの Codex で開発する visionOS アプリの開発スタイルについて
karad
0
150
Featured
See All Featured
Designing Powerful Visuals for Engaging Learning
tmiket
1
500
Git: the NoSQL Database
bkeepers
PRO
432
67k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
370
The SEO Collaboration Effect
kristinabergwall1
1
520
Building AI with AI
inesmontani
PRO
1
1.1k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
64
56k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
Believing is Seeing
oripsolob
1
190
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
57k
A designer walks into a library…
pauljervisheath
211
24k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
Transcript
実行場所を意識させないi18n APIを作った話 colocaleというOSSを作りました © 2026 ANDPAD All Rights Reserved. Confidential
自己紹介 | Speaker 柿森 隆生 GitHub | Urotea ポジション: TechLead(プロダクトのためになんでもやる人)
最近よく書いている言語: skills(言語なのか?) 趣味: LoL / OW © 2026 ANDPAD All Rights Reserved. Confidential 2
ただ表示する言葉を変えるだけのはずだった どの言語を表示するかの分岐はスコープ外とさせてください。 今回の話は言語ごとにラベルを入れ替えるだけの小さな部品の話です。 ラベルを日本語と英語で切り替えたい 該当のコンポーネントはサーバーコンポーネントからもクライアントからも使いたい next-intlのようなi18nライブラリは、サーバーとクライアントでAPIが分かれているので、コンポーネントが 動く場所を意識せざるを得ない さらにプラグインの追加やProviderの追加も必要になる ラベルを差し替えるだけなのに、なぜか設計の話になった。 ©
2026 ANDPAD All Rights Reserved. Confidential 3
動く場所を先に決めさせられる | next-intl の場合 'use client'; // ← これでサーバーから使えなくなる import
{ useTranslations } from 'next-intl'; export const ReportListItem = (props: Props) => { const t = useTranslations('report'); // ← サーバーでは getTranslations return ( <li> <span>{t('date')}:{props.date}</span> <span>{t('count', { count: props.count })}</span> </li> ); }; クライアントは useTranslations 、サーバーは getTranslations と関数が分かれる 加えて next.config へのプラグイン追加と、Provider がもう一段 © 2026 ANDPAD All Rights Reserved. Confidential 4
動く場所を意識させるAPIは再利用性を殺す 先の例のような小さな部品ほど、サーバーとクライアントの両方で使いたい なのにi18nのAPIが場所ごとに分かれていると、部品が動く場所に縛られる サーバーとクライアントで実行モデルが違うのは当然。問題はその違いをコンポーネント自身に意識させてい ること プラグインやProviderの追加も不要で、実行場所を意識せず、ラベルを差し替えるだけのAPIが欲しい © 2026 ANDPAD All
Rights Reserved. Confidential 5
単純に引数で渡す | colocale import { createTranslator, type Messages } from
'colocale'; import { reportItemTranslations } from './translations'; export const ReportListItem = (props: Props & { messages: Messages }) => { const t = createTranslator(props.messages, reportItemTranslations); return ( <li> <span>{t('date')}:{props.date}</span> <span>{t('count', { count: props.count })}</span> </li> ); }; 場所を知る責任が呼び出し側に移り、コンポーネントはどこでも動く 利用する辞書は translations.ts に置く: defineRequirement('report', ['date', 'count']) © 2026 ANDPAD All Rights Reserved. Confidential 6
代償とまだ解けていないこと Propsに messages が増える。いわゆるバケツリレー requirementを取り違えて絞ると、型は通るのに実行時にキーが足りない Messages 型がrequirementでパラメータ化されていないため 回避策はある: requirementを大きめの粒度で作ったり、requirementを省略して指定言語の全辞書を渡す(小 規模ならこれで十分)
宿題: 足りないキーをコンパイルエラーにする方法を探しています。心当たりのある方は教えてください。 © 2026 ANDPAD All Rights Reserved. Confidential 7
まとめ RSC時代に欲しかったのは、動く場所を知らなくていいi18n API Providerを捨てて引数で渡すだけで、同じコンポーネントがサーバーでもクライアントでも動く 副産物として、React以外でも同じ書き方が使える(Vueにも対応) colocale github.com/Urotea/colocale おまけ: 翻訳をYAMLで書いてJSONに変換するyamlocaleも公開しています(i18next /
react-intl / vue-i18n でも使えます) github.com/Urotea/yamlocale © 2026 ANDPAD All Rights Reserved. Confidential 8