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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
ANDPAD inc
August 21, 2026
Programming
56
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
380
言語を使う側から、作る側へ。 自作 Lisp で得た新たな気づき。
andpad
0
180
OS アップデート対応の取り組み方がもっと共有されてほしい
andpad
0
140
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
560
ANDPAD Ruby sponsor session in RubyKaigi 2026
andpad
0
260
AWS WAFの運用を地道に改善し、自社で運用可能にするプラクティス
andpad
2
1.3k
アプリから 360 度カメラ「RICOH THETA」に接続して写真を撮影する
andpad
0
90
アンドパッドが提供する Drinks and Local Meals と Drinkup を大公開
andpad
0
160
建設DXを支えるANDPAD: 2025年のセキュリティの取り組みと卒業したいセキュリティ
andpad
0
620
Other Decks in Programming
See All in Programming
Go 1.27からのGODEBUG / Go 1.27 リリースパーティ #go127party
mazrean
0
320
一参加者から『中の人』へ 〜全通PHPerがブースに立って学んだ、カンファレンスを100倍楽しむコツ〜
wp_daisuke
0
120
信頼性の目標を誰も求めてない
shubox
0
490
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
6
2.5k
From 6 People Classroom Meetup to 100 People Regional Conference / FOSS4G Hiroshima 2026
furukawayasuto
0
110
「つくるAI」だけではバグは見つからない ~テストに必要な「見つけるAI」を分離させる戦略~
mfunaki
0
230
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
0
390
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
360
RSSとCodexを使ってX投稿自動化してみた
ochtum
0
110
AIエージェント時代のコードレビューを設計する
nogu66
6
2.5k
ハーネス設計入門 〜プロンプト、コンテキストの次〜
kinopeee
55
36k
週末にAI-DLCを本気で回したら$1,600溶けた
hbashimizu
0
130
Featured
See All Featured
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
290
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
770
Leo the Paperboy
mayatellez
8
2.2k
Mind Mapping
helmedeiros
1
350
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
450
Ethics towards AI in product and experience design
skipperchong
2
360
Joys of Absence: A Defence of Solitary Play
codingconduct
1
480
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
Context Engineering - Making Every Token Count
addyosmani
9
1.1k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
540
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