Skip to content
Open
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
1 change: 1 addition & 0 deletions layer/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export default defineAppConfig({
locale: 'en',
ui: {
colors: {
primary: 'emerald',
Expand Down
8 changes: 5 additions & 3 deletions layer/app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ const { seo } = useAppConfig()
const site = useSiteConfig()
const { locale, locales, isEnabled, switchLocalePath } = useDocusI18n()

const lang = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.code || 'en')
const dir = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.dir || 'ltr')
const matchedUiLocale = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales])
const uiLocale = computed(() => matchedUiLocale.value || nuxtUiLocales.en)
const lang = computed(() => matchedUiLocale.value.code || 'en')
const dir = computed(() => matchedUiLocale.value?.dir || 'ltr')
const collectionName = computed(() => isEnabled.value ? `docs_${locale.value}` : 'docs')

useHead({
Expand Down Expand Up @@ -58,7 +60,7 @@ provide('navigation', navigation)
</script>

<template>
<UApp :locale="nuxtUiLocales[locale as keyof typeof nuxtUiLocales]">
<UApp :locale="uiLocale">
<NuxtLoadingIndicator color="var(--ui-primary)" />

<AppHeader v-if="$route.meta.header !== false" />
Expand Down
1 change: 1 addition & 0 deletions layer/app/components/LanguageSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function getEmojiFlag(locale: string): string {
uk: 'ua', // Ukrainian -> Ukraine
ur: 'pk', // Urdu -> Pakistan
vi: 'vn', // Vietnamese -> Vietnam
es: 'es', // Spanish -> Spain
}

const baseLanguage = locale.split('-')[0]?.toLowerCase() || locale
Expand Down
30 changes: 28 additions & 2 deletions layer/app/composables/useDocusI18n.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
import type { LocaleObject } from '@nuxtjs/i18n'
import en from '../../i18n/locales/en.json'

type LocaleMessages = typeof en

const localeFiles = import.meta.glob('../../i18n/locales/*.json', {
import: 'default',
eager: true,
}) as Record<string, LocaleMessages>

const localeMessages = Object.entries(localeFiles).reduce<Record<string, LocaleMessages>>((acc, [path, messages]) => {
const localeCode = path.split('/').pop()?.replace('.json', '')
if (localeCode) {
acc[localeCode] = messages
}
return acc
}, {})

export const useDocusI18n = () => {
const config = useRuntimeConfig().public
const appConfig = useAppConfig()
const isEnabled = ref(!!config.i18n)

if (!isEnabled.value) {
const configuredLocale = appConfig.locale
const messages = localeMessages[configuredLocale]

if (!messages && configuredLocale !== 'en') {
console.warn(`[Docus] Missing locale file for "${configuredLocale}". Falling back to "en".`)
}

const locale = messages ? configuredLocale : 'en'
const resolvedMessages = messages || en

return {
isEnabled,
locale: ref('en'),
locale: ref(locale),
locales: [],
localePath: (path: string) => path,
switchLocalePath: () => {},
t: (key: string): string => {
const path = key.split('.')
return path.reduce((acc: unknown, curr) => (acc as Record<string, unknown>)?.[curr], en) as string
return path.reduce((acc: unknown, curr) => (acc as Record<string, unknown>)?.[curr], resolvedMessages) as string
},
}
}
Expand Down
6 changes: 5 additions & 1 deletion layer/app/error.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ const props = defineProps<{

const { locale, locales, isEnabled, t, switchLocalePath } = useDocusI18n()

const matchedUiLocale = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales])
const uiLocale = computed(() => matchedUiLocale.value || nuxtUiLocales.en)

const lang = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.code || 'en')
const dir = computed(() => nuxtUiLocales[locale.value as keyof typeof nuxtUiLocales]?.dir || 'ltr')
useHead({
Expand All @@ -22,6 +25,7 @@ const localizedError = computed(() => {
return {
...props.error,
statusMessage: t('common.error.title'),
message: t('common.error.description'),
}
})

Expand Down Expand Up @@ -59,7 +63,7 @@ provide('navigation', navigation)
</script>

<template>
<UApp>
<UApp :locale="uiLocale">
<AppHeader />

<UError :error="localizedError" />
Expand Down
1 change: 1 addition & 0 deletions layer/app/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
declare module 'nuxt/schema' {
interface AppConfig {
locale: string
seo: {
titleTemplate: string
title: string
Expand Down
22 changes: 22 additions & 0 deletions layer/i18n/locales/es.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"common": {
"or": "o",
"error": {
"title": "Página no encontrada",
"description": "Lo sentimos, no se pudo encontrar esta página."
}
},
"docs": {
"copy": {
"page": "Copiar página",
"link": "Copiar página en Markdown",
"view": "Ver como Markdown",
"gpt": "Abrir en ChatGPT",
"claude": "Abrir en Claude"
},
"links": "Comunidad",
"toc": "En esta página",
"report": "Reportar un problema",
"edit": "Editar esta página"
}
}
7 changes: 7 additions & 0 deletions layer/nuxt.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import { field, group } from '@nuxt/content/preview'

export default defineNuxtSchema({
appConfig: {
locale: field({
type: 'string',
title: 'Locale',
description: 'Locale to use when @nuxtjs/i18n is not being used.',
icon: 'i-lucide-languages',
default: 'en',
}),
ui: group({
title: 'UI',
description: 'UI Customization.',
Expand Down