Skip to content

Commit 0bdf068

Browse files
authored
Merge pull request #181 from vim-jp/i18n
1ページでの多言語対応
2 parents 79daf1c + dd72e92 commit 0bdf068

File tree

5 files changed

+259
-351
lines changed

5 files changed

+259
-351
lines changed

2025/src/components/LanguagePicker.astro

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
11
---
2+
import { LANGUAGES } from '@/i18n';
23
// @ts-expect-error not found
34
import { base } from 'astro:config/client';
45
5-
const languages
6-
= Object.keys(import.meta.glob('../pages/*.astro'))
7-
.map(p => p.split('/')
8-
.at(-1)!
9-
.replace('.astro', ''))
10-
.filter(lang => lang !== 'index')
11-
.sort();
126
const pathname = Astro.url.pathname.replace(import.meta.env.BASE_URL, '');
137
const currentLang = pathname.split('/')[1];
8+
149
---
1510
<div class="language-switcher">
16-
{languages.map((lang, i) => (
11+
{LANGUAGES.map((lang, i) => (
1712
<>
1813
<a href={`${base as string}/${lang}/`} class:list={{ active: lang === currentLang }}>
1914
{lang.toUpperCase()}
2015
</a>
21-
{i < languages.length - 1 && <span class="separator">/</span>}
22-
</>
16+
{i < LANGUAGES.length - 1 && <span class="separator">/</span>}
17+
</>
2318
))}
2419
</div>
2520

2025/src/i18n/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const LANGUAGES = ['ja', 'en'] as const;
2+
3+
type Lang = typeof LANGUAGES[number];
4+
5+
export function useTranslate(lang: Lang): (...translations: string[]) => string {
6+
return (...translations: string[]) => translations[LANGUAGES.indexOf(lang)]; ;
7+
}

2025/src/pages/[lang]/index.astro

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
---
2+
import AnnouncementSlides from '@/components/AnnouncementSlides.astro';
3+
import VenueMap from '@/components/VenueMap.astro';
4+
import { MAIN_BACKGROUND_COLOR } from '@/consts';
5+
import { LANGUAGES, useTranslate } from '@/i18n';
6+
7+
import Layout from '@/layouts/Layout.astro';
8+
9+
export function getStaticPaths() {
10+
return LANGUAGES.map(lang => ({ params: { lang } }));
11+
}
12+
13+
const { lang } = Astro.params;
14+
const t = useTranslate(lang);
15+
---
16+
17+
<Layout>
18+
<section>
19+
<div class="container">
20+
<h2 id="what-is-vimconf-2025" class="section-title">
21+
<a href="#what-is-vimconf-2025">
22+
{t('VimConf 2025 とは?', 'What is VimConf 2025?')}
23+
</a>
24+
</h2>
25+
<p>
26+
{t(
27+
'VimConf は、世界初かつ世界で唯一のコミュニティによって定期運営されているVimの国際カンファレンスです。',
28+
`VimConf is the world's first and only regularly organized international Vim conference run by the community.`,
29+
)}
30+
</p>
31+
<h3>{t('概要', 'Event Details')}</h3>
32+
<table>
33+
<caption>
34+
{t('VimConf 2025の概要', 'Details Of VimConf 2025')}
35+
</caption>
36+
<tr>
37+
<th style="word-break:keep-all;">
38+
{t('開催日(予定)', 'Date(Planned)')}
39+
</th>
40+
<td>{t('2025年11月2日(日)', 'November 2, 2025 (Sunday)')}</td>
41+
</tr>
42+
<tr>
43+
<th>{t('時間', 'Time')}</th>
44+
<td>{t(
45+
'9:30 - 17:30 (懇親会: 17:30 - 19:30)',
46+
'9:30 AM - 5:30 PM JST (Networking Party: 5:30 PM - 7:30 PM JST)',
47+
)}</td>
48+
</tr>
49+
<tr>
50+
<th>{t('会場', 'Venue')}</th>
51+
<td>
52+
<a href="https://www.fsi.co.jp/akibaplaza/hall.html">
53+
{t(
54+
'アキバプラザ・アキバホール',
55+
'Akiba Plaza - Akiba Hall',
56+
)}
57+
</a>
58+
<a>{/* XXX: Workaround for https://github.com/withastro/compiler/issues/958 */}</a>
59+
</td>
60+
</tr>
61+
</table>
62+
<VenueMap />
63+
<h3>{t('その他', 'Additional Information')}</h3>
64+
<p>{t(
65+
'発表スライドはすべて英語です。発表は英語または日本語のいずれかの言語で行われます。',
66+
'All presentation slides will be in English. Presentations will be given in either English or Japanese.',
67+
)}</p>
68+
<p>{t(
69+
'登壇の様子を撮影し、後日 YouTube にアップロードします。',
70+
'The presentations will be recorded and uploaded to YouTube after the event.',
71+
)}</p>
72+
<p>{t(
73+
'会場内ではカメラマンによる写真撮影が行われますのでご了承ください。',
74+
'Please note that professional photographers will be taking pictures during the event.',
75+
)}</p>
76+
<p>{t(
77+
'写真もまとめてWeb上に掲載されます。',
78+
'Photos will be published online after the event.',
79+
)}</p>
80+
</div>
81+
</section>
82+
83+
<section>
84+
<div class="container">
85+
<h2 id="why-we-need-sponsors" class="section-title">
86+
<a href="#why-we-need-sponsors">
87+
{t('なぜスポンサーが必要なのか?', 'Why We Need Sponsors')}
88+
</a>
89+
</h2>
90+
<p>
91+
{t(
92+
'VimConf 2025は、普段なかなか顔を合わせられないVimmer同士が情熱を交わし、知見を共有するための貴重な場です。\n今年は、イベント継続の担保と柔軟な運営のため、必要な資金をスポンサー様のご支援で集める仕組みを採用します。',
93+
'VimConf 2025 is a valuable opportunity for Vimmers, who rarely get to meet in person, to share their passion and knowledge.\nThis year, to ensure the event\'s sustainability and flexible operation, we are seeking financial support through sponsorships.',
94+
)}
95+
</p>
96+
</div>
97+
</section>
98+
99+
<section>
100+
<div class="container sponsor-info">
101+
<h2 id="sponsorship-overview" class="section-title">
102+
<a href="#sponsorship-overview">
103+
{t(
104+
'スポンサーシップ概要',
105+
'Sponsorship Overview',
106+
)}
107+
</a>
108+
</h2>
109+
<h3>{t(
110+
'募集期間と判断タイミング:',
111+
'Application Period and Decision Timeline:',
112+
)}</h3>
113+
<p>
114+
{t(
115+
'スポンサーの募集は既に開始されています。イベントは、必要な支援金が集まった場合にのみ開催します。\n開催の最終判断は2025年5月15日(木)に行います。',
116+
'Sponsor recruitment is already underway. The event will only be held if we receive sufficient sponsorship support.\nThe final decision on the event will be made on May 15, 2025 (Thursday).',
117+
)}
118+
</p>
119+
<h3>{t('ご提供いただく支援:', 'Sponsorship Benefits:')}</h3>
120+
<p>
121+
{t(
122+
'スポンサーシップに応じたメリット(公式サイトでのロゴ掲載、ノベルティの配布、バックパネルへのロゴ掲載など)を用意しています。\nイベント開催のための資金として、ぜひご協力ください。\n※ また、併せて個人による寄付の募集も行っています。(開催されなかった場合でも返金不可)',
123+
'We offer various benefits depending on the sponsorship level (including logo placement on the official website, distribution of promotional materials, logo display on the backdrop, etc.).\nPlease consider supporting us to make this event possible.\n※ Individual sponsorships are also available. (Please note that sponsorships are non-refundable even if the event is canceled)',
124+
)}
125+
</p>
126+
<p>
127+
{t(
128+
'ご支援いただける方は、以下のリンクからお願いいたします。',
129+
'If you would like to support us as a personal sponsor, please follow the link below.',
130+
)}
131+
</p>
132+
<p style="text-align: center;">
133+
<a class="btn" href="https://vimconf.booth.pm/" target="blank">
134+
{t('寄付をする', 'become a personal sponsor')}
135+
</a>
136+
</p>
137+
<p>
138+
<b>
139+
{t(
140+
'初の試みですので、',
141+
'As this is our first initiative of this kind,',
142+
)}
143+
</b>
144+
{t(
145+
'ご不明な点やご質問があればご遠慮なくお問い合わせください。',
146+
`please don't hesitate to contact us with any questions or concerns.`,
147+
)}
148+
</p>
149+
</div>
150+
</section>
151+
152+
<section id="contact">
153+
<div class="container">
154+
<h2 class="section-title">{t('スポンサーに関するお問い合わせ', 'Sponsorship Inquiries')}</h2>
155+
<p>
156+
{t(
157+
'スポンサーシップに関するご質問、ご提案などにつきましては、下記のフォームまたはメールにてお気軽にお問い合わせください。\n※最新情報は随時更新していきます。',
158+
'For questions or proposals regarding sponsorship, please feel free to contact us through the form below or via email.\n※ Information will be updated regularly.',
159+
)}
160+
</p>
161+
<AnnouncementSlides />
162+
<p style="text-align: center;">
163+
<a class="btn" href="https://docs.google.com/forms/d/e/1FAIpQLSfPMjGwsmjOhzxXf_e65uyIb0ml35iIdCYq5EEoSI4KompK3w/viewform" target="blank">
164+
{t('お問い合わせフォームへ', 'Contact Form')}
165+
</a>
166+
</p>
167+
</div>
168+
</section>
169+
</Layout>
170+
171+
<style define:vars={{ mainBackgroundColor: MAIN_BACKGROUND_COLOR }}>
172+
h3 {
173+
font-size: 1.2rem;
174+
}
175+
176+
/* Container */
177+
.container {
178+
width: 90%;
179+
max-width: 960px;
180+
margin: auto;
181+
padding: 24px 0;
182+
}
183+
184+
/* Section Title */
185+
.section-title {
186+
font-size: 2.4rem;
187+
border-bottom: 2px solid #ccc;
188+
189+
a {
190+
text-decoration: none;
191+
color: inherit;
192+
}
193+
}
194+
195+
/* Common Section Styles */
196+
section {
197+
padding: 50px 0;
198+
background-color: #fff;
199+
200+
&:nth-of-type(even) {
201+
background: #f1f9f1;
202+
}
203+
}
204+
205+
section + section {
206+
margin-top: 16px;
207+
}
208+
209+
/* Contact Button */
210+
.btn {
211+
display: inline-block;
212+
background-color: var(--mainBackgroundColor);
213+
color: #fff;
214+
padding: 12px 20px;
215+
border-radius: 4px;
216+
}
217+
218+
table {
219+
width: 100%;
220+
border-collapse: collapse;
221+
margin: 12px 0;
222+
}
223+
224+
table th,
225+
table td {
226+
border: 1px solid #ccc;
227+
padding: 12px;
228+
text-align: left;
229+
}
230+
231+
table th {
232+
background-color: #f2f2f2;
233+
font-weight: bold;
234+
}
235+
236+
/* Responsive Adjustments */
237+
@media (max-width: 600px) {
238+
.hero h1 {
239+
font-size: 3rem;
240+
}
241+
242+
.section-title {
243+
font-size: 1.6rem;
244+
}
245+
}
246+
247+
</style>

0 commit comments

Comments
 (0)