import { locale, t } from '@/i18n' import type { ResolvedSeo } from '@/lib/seoTypes' import { languageName } from '@/lib/siteLanguages' import { nameInSentence } from '@/lib/storyList' export interface LocalizedSeoContext { lang: string siteName: string siteKey: string pattern: string | null defaultLang: string disabledLangs: string[] published: boolean socialState: string resolved: ResolvedSeo | null } export function pageLanguage(context: LocalizedSeoContext) { return languageName(context.lang, locale.value) } export function breadcrumbOf(url: string) { try { const parsed = new URL(url) const segments = parsed.pathname.split('/').filter(Boolean) return [parsed.host, ...segments].join(' › ') } catch { return url } } export function canonicalNote(context: LocalizedSeoContext) { if (context.resolved?.fallbacks.canonical === 'canonical_url') { return t('Set by hand as a canonical override on this version.') } return t( 'Built from the Public URL pattern {0}. Each language points to itself unless you set a canonical override.', [context.pattern ?? ''], ) } export function disabledNote(context: LocalizedSeoContext) { if (context.disabledLangs.length === 0) { return t('Drafts are left out.') } const names = context.disabledLangs.map((tag) => nameInSentence(tag)) const list = names.join(', ') return names.length === 1 ? t('Drafts and the disabled {0} language are left out.', [list]) : t('Drafts and the disabled languages {0} are left out.', [list]) } export function socialLocaleLine(context: LocalizedSeoContext) { const value = context.resolved?.og.locale ?? '' if (!value) { return t('Social locale not set') } return context.socialState === 'derived' ? t('Derived: {0}', [value]) : t('Set: {0}', [value]) } export function socialLocaleNote(context: LocalizedSeoContext) { const name = pageLanguage(context) if (!context.resolved?.og.locale) { return t( '{0} has no region in its code and no social locale is set for it, so og:locale and og:locale:alternate are left out. An owner can set one in {1} languages.', [name, context.siteName], ) } if (context.socialState === 'derived') { return t( 'Taken from the region of the language code or of the site locale. An owner can set another in {0} languages.', [context.siteName], ) } return t( 'Set by an owner for {0} in {1} languages. A region is never guessed from the language.', [name, context.siteName], ) } export function titleHelp(context: LocalizedSeoContext) { const source = context.resolved?.fallbacks.title return source === 'title' ? t('Fallback: {0} title', [nameInSentence(context.lang)]) : '' } export function descriptionHelp(context: LocalizedSeoContext) { const fallbacks = context.resolved?.fallbacks if (!fallbacks) { return '' } const name = nameInSentence(context.lang) switch (fallbacks.description) { case 'excerpt': return t('Fallback: {0} excerpt', [name]) case 'body': return t('Fallback: {0} body', [name]) case 'site': return t('Fallback: {0} site description', [name]) case 'none': return fallbacks.site_text_skipped ? t('No fallback. Empty. {0} site default not used. The tag is left out.', [ nameInSentence(context.defaultLang), ]) : t('No fallback') default: return '' } } export function descriptionBadge(context: LocalizedSeoContext) { const fallbacks = context.resolved?.fallbacks if (fallbacks?.description === 'site') { return t('Uses site text') } return fallbacks?.site_text_skipped ? t('Tag left out') : '' } export function altHelp() { return t('Written per language.') }