Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add i18n #110

Merged
merged 15 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 43 additions & 2 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,47 @@
/** @type { import('@storybook/vue3').Preview } */
import '../app/assets/css/reset.css'
import '../app/assets/css/main.css'
import '@/assets/css/reset.css'
import '@/assets/css/main.css'

export const globalTypes = {
theme: {
name: 'Theme',
description: 'Global theme for components',
defaultValue: 'light',
toolbar: {
icon: 'cog',
items: ['light', 'dark'],
dynamicTitle: true,
},
},
locale: {
name: 'Locale',
description: 'Internationalization locale for components',
defaultValue: 'ja',
toolbar: {
icon: 'globe',
items: ['ja', 'en'],
dynamicTitle: true,
},
},
}

const themeDecorator = (story, context) => {
const theme = context.globals.theme || 'light'
document.documentElement.classList.remove('light-mode', 'dark-mode')
document.documentElement.classList.add(`${theme}-mode`)
return story()
}

const localeDecorator = (story, context) => {
const locale = context.globals.locale || 'ja'
document.documentElement.lang = locale
return story()
}

export const decorators = [
themeDecorator,
localeDecorator,
]

const preview = {
parameters: {
Expand Down
1 change: 1 addition & 0 deletions app/assets/images/language.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 4 additions & 16 deletions app/components/calendar-heatmap.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
<script setup lang="ts">
const props = defineProps({
targetYear: {
type: Number,
required: true,
},
activeDates: {
type: Array as () => string[],
required: true,
},
title: {
type: String,
required: true,
},
})
import type { CalendarHeatmapProps } from '@/types'

const props = defineProps<CalendarHeatmapProps>()

const date = new Date()
const thisYear = date.getFullYear()
Expand Down Expand Up @@ -187,9 +176,8 @@ const setTooltipPosition = (event: MouseEvent) => {
</ul>
</div>
<p class="annotation">
※本ブログにおける
<span>{{ title }}</span>
の記事の執筆および編集のアクティビティです。
{{ $t('annotation') }}
</p>
</div>
</template>
Expand Down
4 changes: 2 additions & 2 deletions app/components/footer.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<template>
<footer class="footer">
<NuxtLink
<NuxtLinkLocale
to="/terms-and-privacy"
class="terms-and-privacy"
>
Terms and Privacy
</NuxtLink>
</NuxtLinkLocale>
<p class="copyright">
&copy; 2024 Hikaru Kobayashi.
</p>
Expand Down
26 changes: 20 additions & 6 deletions app/components/header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,25 @@ onUnmounted(() => {
<template>
<header>
<div class="wrapper">
<NuxtLink
<NuxtLinkLocale
to="/"
class="link"
>
Blog
</NuxtLink>
</NuxtLinkLocale>
<nav class="navigation">
<NuxtLink
<NuxtLinkLocale
to="/about"
class="link"
>
About
</NuxtLink>
<NuxtLink
</NuxtLinkLocale>
<NuxtLinkLocale
to="/tags"
class="link"
>
Tags
</NuxtLink>
</NuxtLinkLocale>
<IconButton
element="button"
label="記事を検索する"
Expand Down Expand Up @@ -159,6 +159,20 @@ onUnmounted(() => {
>
</template>
</IconButton>
<IconButton
element="button"
:label="$i18n.locale === 'ja' ? 'Switch to English' : '日本語に切り替える'"
@on-click="$i18n.setLocale($i18n.locale === 'ja' ? 'en' : 'ja')"
>
<template #icon>
<img
width="16"
height="16"
src="@/assets/images/language.svg"
alt=""
>
</template>
</IconButton>
<IconButton
v-if="$colorMode.value === 'light' || $colorMode.preference === 'light'"
element="button"
Expand Down
21 changes: 4 additions & 17 deletions app/components/link-to-back.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
<script setup lang="ts">
defineProps({
to: {
type: String,
required: true,
},
text: {
type: String,
required: true,
},
})
</script>

<template>
<NuxtLink
:to="to"
<NuxtLinkLocale
to="/"
class="link-to-back"
>
{{ text }}
</NuxtLink>
{{ $t('linkToBack') }}
</NuxtLinkLocale>
</template>

<style scoped>
Expand Down
2 changes: 1 addition & 1 deletion app/components/link-to-edit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defineProps({
width="20"
height="20"
>
GitHubで編集を提案する
{{ $t('linkToEdit') }}
</a>
</template>

Expand Down
2 changes: 1 addition & 1 deletion app/components/sort-menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defineEmits<{
:aria-label="desc ? '昇順に並び替える' : '降順に並び替える'"
@click="$emit('toggleSort')"
/>
<p>作成日時</p>
<p>{{ $t('createdAt') }}</p>
</div>
</template>

Expand Down
2 changes: 1 addition & 1 deletion app/components/tag-menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ onClickOutside(target, () => {
type="button"
@click="toggleVisibility()"
>
タグで絞り込む
{{ $t('filterByTag') }}
</button>
<Transition appear>
<ul
Expand Down
2 changes: 1 addition & 1 deletion app/components/tag.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const component = computed(() => {
}
case 'nuxt-link':
return {
element: resolveComponent('NuxtLink'),
element: resolveComponent('NuxtLinkLocale'),
props: nuxtLinkProps,
}
default: {
Expand Down
16 changes: 3 additions & 13 deletions app/components/toc.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
<script setup lang="ts">
type Props = {
items: {
title: string
searchDepth: number
links: {
id: string
depth: number
text: string
}[]
}
}
import type { TocProps } from '@/types'

defineProps<Props>()
defineProps<TocProps>()

/**
* クリックされたリンクのid属性名に対応する要素までスクロールさせる
Expand All @@ -32,7 +22,7 @@ const scrollToTarget = (id: string) => {

<template>
<nav class="toc">
<p>目次</p>
<p>{{ $t('toc') }}</p>
<ul>
<li
v-for="(link, index) in Array.from(items?.links)"
Expand Down
17 changes: 10 additions & 7 deletions app/pages/[slug].vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
<script setup lang="ts">
// 現在のページを取得する
const route = useRoute()
const { locale } = useI18n()

// 現在のページを取得する
const targetPath = computed(() => {
if (locale.value === 'en') return '/en'
return '/'
})

/**
* 現在のページの前後のページ情報を取得する
*/
const { data, error } = await useAsyncData('slug', () =>
queryContent('/')
queryContent(targetPath.value)
.only(['_path', 'title', 'description'])
.findSurround(route.path),
)
Expand Down Expand Up @@ -48,7 +54,7 @@ const router = useRouter()
</div>
<div class="content-wrapper">
<div class="share-button-component">
<p>シェア</p>
<p>{{ $t('share') }}</p>
<ShareButton
title="記事をシェアする"
text="この記事をシェアしよう!"
Expand All @@ -69,10 +75,7 @@ const router = useRouter()
</div>
</article>
<div class="link-box">
<LinkToBack
to="/"
text="一覧に戻る"
/>
<LinkToBack />
<LinkToEdit :file-name="doc._file" />
</div>
</ContentDoc>
Expand Down
19 changes: 13 additions & 6 deletions app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
import type { QueryBuilderParams } from '@nuxt/content/dist/runtime/types'

const route = useRoute()
const title = route.query.tag ? `${route.query.tag}` : 'すべて'
const title = route.query.tag ? `${route.query.tag}` : (route.path === '/en' ? 'All' : 'すべて')
const { locale } = useI18n()

// 現在のページを取得する
const targetPath = computed(() => {
if (locale.value === 'en') return '/en'
return '/'
})

useHead({
title: `${title}の記事一覧`,
Expand All @@ -16,8 +23,8 @@ const { desc, toggleSort } = useSort()

const query: QueryBuilderParams = computed(() => {
return {
path: '/',
where: [{ tags: route.query.tag && { $contains: route.query.tag } }],
path: targetPath.value,
where: [{ tags: route.query.tag && { $contains: route.query.tag }, _path: locale.value === 'ja' ? { $not: /^\/en(\/|$)/ } : { $regex: /^\/en(\/|$)/ } }],
sort: [{ createdAt: desc.value ? -1 : 1 }],
}
})
Expand All @@ -29,7 +36,7 @@ const targetYear = ref<number>(date.getFullYear())
* contentディレクトリ配下のコンテンツの全ての情報を取得する
*/
const { data: page } = await useAsyncData('articles', () =>
queryContent('/')
queryContent(targetPath.value)
.where({ tags: route.query.tag && { $contains: route.query.tag } })
.find(),
)
Expand Down Expand Up @@ -63,7 +70,7 @@ const activeDates = computed(() => {
const tags = ref<string[]>([])

const { data } = await useAsyncData('tags', () =>
queryContent('/').only(['tags']).find(),
queryContent(targetPath.value).only(['tags']).find(),
)

if (data.value) {
Expand All @@ -87,7 +94,7 @@ if (data.value) {
<div class="title-wrapper">
<h1 class="title">
{{ title }}
<span>の記事一覧</span>
<span>{{ $t('heading') }}</span>
</h1>
<div class="buttons">
<TagMenu :tags="tags" />
Expand Down
18 changes: 18 additions & 0 deletions app/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,21 @@ export type NavigationMenu = {
text: string
to?: string
}

export type TocProps = {
items: {
title: string
searchDepth: number
links: {
id: string
depth: number
text: string
}[]
}
}

export type CalendarHeatmapProps = {
targetYear: number
activeDates: string[]
title: string
}
2 changes: 2 additions & 0 deletions auto-import-functions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ declare global {
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
const onDeactivated: typeof import('vue')['onDeactivated']
const onElementRemoval: typeof import('@vueuse/core')['onElementRemoval']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
const onLongPress: typeof import('@vueuse/core')['onLongPress']
Expand Down Expand Up @@ -142,6 +143,7 @@ declare global {
const useCloned: typeof import('@vueuse/core')['useCloned']
const useColorMode: typeof import('@vueuse/core')['useColorMode']
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
const useCountdown: typeof import('@vueuse/core')['useCountdown']
const useCounter: typeof import('@vueuse/core')['useCounter']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVar: typeof import('@vueuse/core')['useCssVar']
Expand Down
11 changes: 11 additions & 0 deletions i18n/locales/en.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
filterByTag: 'Filter by Tag',
createdAt: 'Created At',
heading: 'articles list',
all: 'All',
share: 'Share',
toc: 'Table of Contents',
linkToBack: 'Back to home',
linkToEdit: 'Suggest an edit via GitHub',
annotation: 'articles writing and editing activities on this blog.',
}
Loading