Skip to content

Commit 237a79f

Browse files
ComicIvanslarbish
andauthored
feat(i18n): support locale configuration without i18n (#1209)
Co-authored-by: Baptiste Leproux <[email protected]>
1 parent 976f578 commit 237a79f

File tree

7 files changed

+51
-16
lines changed

7 files changed

+51
-16
lines changed

layer/app/app.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
export default defineAppConfig({
2+
docus: {
3+
locale: 'en',
4+
},
25
ui: {
36
colors: {
47
primary: 'emerald',

layer/app/app.vue

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<script setup lang="ts">
2-
import type { PageCollections } from '@nuxt/content'
2+
import type { ContentNavigationItem, PageCollections } from '@nuxt/content'
33
import * as nuxtUiLocales from '@nuxt/ui/locale'
44
55
const { seo } = useAppConfig()
66
const site = useSiteConfig()
77
const { locale, locales, isEnabled, switchLocalePath } = useDocusI18n()
88
9-
const lang = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.code || 'en')
10-
const dir = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.dir || 'ltr')
9+
const nuxtUiLocale = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales] || nuxtUiLocales.en)
10+
const lang = computed(() => nuxtUiLocale.value.code)
11+
const dir = computed(() => nuxtUiLocale.value.dir)
1112
const collectionName = computed(() => isEnabled.value ? `docs_${locale.value}` : 'docs')
1213
1314
useHead({
@@ -43,7 +44,7 @@ if (isEnabled.value) {
4344
}
4445
4546
const { data: navigation } = await useAsyncData(() => `navigation_${collectionName.value}`, () => queryCollectionNavigation(collectionName.value as keyof PageCollections), {
46-
transform: (data) => {
47+
transform: (data: ContentNavigationItem[]) => {
4748
const rootResult = data.find(item => item.path === '/docs')?.children || data || []
4849
4950
return rootResult.find(item => item.path === `/${locale.value}`)?.children || rootResult
@@ -58,7 +59,7 @@ provide('navigation', navigation)
5859
</script>
5960

6061
<template>
61-
<UApp :locale="nuxtUiLocales[locale as keyof typeof nuxtUiLocales]">
62+
<UApp :locale="nuxtUiLocale">
6263
<NuxtLoadingIndicator color="var(--ui-primary)" />
6364

6465
<AppHeader v-if="$route.meta.header !== false" />

layer/app/components/LanguageSelect.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ function getEmojiFlag(locale: string): string {
2828
uk: 'ua', // Ukrainian -> Ukraine
2929
ur: 'pk', // Urdu -> Pakistan
3030
vi: 'vn', // Vietnamese -> Vietnam
31+
es: 'es', // Spanish -> Spain
3132
}
3233
3334
const baseLanguage = locale.split('-')[0]?.toLowerCase() || locale

layer/app/composables/useDocusI18n.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
import type { LocaleObject } from '@nuxtjs/i18n'
2-
import en from '../../i18n/locales/en.json'
32

43
export const useDocusI18n = () => {
54
const config = useRuntimeConfig().public
65
const isEnabled = ref(!!config.i18n)
76

87
if (!isEnabled.value) {
8+
const locale = useNuxtApp().$locale as string
9+
const localeMessages = useNuxtApp().$localeMessages as Record<string, unknown>
10+
911
return {
1012
isEnabled,
11-
locale: ref('en'),
13+
locale: ref(locale),
1214
locales: [],
1315
localePath: (path: string) => path,
1416
switchLocalePath: () => {},
1517
t: (key: string): string => {
1618
const path = key.split('.')
17-
return path.reduce((acc: unknown, curr) => (acc as Record<string, unknown>)?.[curr], en) as string
19+
return path.reduce((acc: unknown, curr) => (acc as Record<string, unknown>)?.[curr], localeMessages) as string
1820
},
1921
}
2022
}

layer/app/error.vue

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script setup lang="ts">
22
import type { NuxtError } from '#app'
3-
import type { PageCollections } from '@nuxt/content'
3+
import type { ContentNavigationItem, PageCollections } from '@nuxt/content'
44
import * as nuxtUiLocales from '@nuxt/ui/locale'
55
66
const props = defineProps<{
@@ -9,8 +9,10 @@ const props = defineProps<{
99
1010
const { locale, locales, isEnabled, t, switchLocalePath } = useDocusI18n()
1111
12-
const lang = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.code || 'en')
13-
const dir = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.dir || 'ltr')
12+
const nuxtUiLocale = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales] || nuxtUiLocales.en)
13+
const lang = computed(() => nuxtUiLocale.value.code)
14+
const dir = computed(() => nuxtUiLocale.value.dir)
15+
1416
useHead({
1517
htmlAttrs: {
1618
lang,
@@ -22,6 +24,7 @@ const localizedError = computed(() => {
2224
return {
2325
...props.error,
2426
statusMessage: t('common.error.title'),
27+
message: t('common.error.description'),
2528
}
2629
})
2730
@@ -44,7 +47,7 @@ if (isEnabled.value) {
4447
const collectionName = computed(() => isEnabled.value ? `docs_${locale.value}` : 'docs')
4548
4649
const { data: navigation } = await useAsyncData(`navigation_${collectionName.value}`, () => queryCollectionNavigation(collectionName.value as keyof PageCollections), {
47-
transform: (data) => {
50+
transform: (data: ContentNavigationItem[]) => {
4851
const rootResult = data.find(item => item.path === '/docs')?.children || data || []
4952
5053
return rootResult.find(item => item.path === `/${locale.value}`)?.children || rootResult
@@ -59,7 +62,7 @@ provide('navigation', navigation)
5962
</script>
6063

6164
<template>
62-
<UApp>
65+
<UApp :locale="nuxtUiLocale">
6366
<AppHeader />
6467

6568
<UError :error="localizedError" />

layer/app/plugins/i18n.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,34 @@
1-
export default defineNuxtPlugin(() => {
1+
import en from '../../i18n/locales/en.json'
2+
import type { RouteLocationNormalized } from 'vue-router'
3+
4+
export default defineNuxtPlugin(async () => {
25
const nuxtApp = useNuxtApp()
36

47
const i18nConfig = nuxtApp.$config.public.i18n
8+
9+
// If i18n is not enabled, fetch and provide the configured locale in app config
510
if (!i18nConfig) {
6-
return
11+
let locale = 'en'
12+
let resolvedMessages: Record<string, unknown> = en
13+
14+
const appConfig = useAppConfig()
15+
const configuredLocale = appConfig.docus.locale
16+
if (configuredLocale !== 'en') {
17+
const localeMessages = await import(`../../i18n/locales/${configuredLocale}.json`)
18+
if (!localeMessages) {
19+
console.warn(`[Docus] Missing locale file for "${configuredLocale}". Falling back to "en".`)
20+
}
21+
else {
22+
locale = configuredLocale
23+
resolvedMessages = localeMessages
24+
}
25+
}
26+
27+
nuxtApp.provide('locale', locale)
28+
nuxtApp.provide('localeMessages', resolvedMessages)
729
}
830

9-
addRouteMiddleware((to) => {
31+
addRouteMiddleware((to: RouteLocationNormalized) => {
1032
if (to.path === '/') {
1133
const cookieLocale = useCookie('i18n_redirected').value || i18nConfig.defaultLocale || 'en'
1234

layer/app/types/index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
declare module 'nuxt/schema' {
22
interface AppConfig {
3+
docus: {
4+
locale: string
5+
}
36
seo: {
47
titleTemplate: string
58
title: string

0 commit comments

Comments
 (0)