Refactor languages module: separate client and server code (#57949)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -4,14 +4,9 @@ import type { NextConfig } from 'next'
|
||||
|
||||
import frontmatter from '@gr2m/gray-matter'
|
||||
import { getLogLevelNumber } from '@/observability/logger/lib/log-levels'
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
|
||||
const ROOT = process.env.ROOT || '.'
|
||||
|
||||
// Language keys are defined here because Next.js config compilation doesn't resolve the @/ path alias
|
||||
// Importing from src/languages/lib/languages.ts would fail when it tries to import @/frame/lib/constants
|
||||
// This must match the languages defined in src/languages/lib/languages.ts
|
||||
const languageKeys = ['en', 'es', 'ja', 'pt', 'zh', 'ru', 'fr', 'ko', 'de']
|
||||
|
||||
const homepage = path.posix.join(ROOT, 'content/index.md')
|
||||
const { data } = frontmatter(fs.readFileSync(homepage, 'utf8'))
|
||||
const productIds = data.children as string[]
|
||||
|
||||
@@ -10,7 +10,7 @@ import { initializeEvents } from '@/events/components/events'
|
||||
import { CTAPopoverProvider } from '@/frame/components/context/CTAContext'
|
||||
import { SharedUIContextProvider } from '@/frame/components/context/SharedUIContext'
|
||||
import { LanguagesContext, LanguagesContextT } from '@/languages/components/LanguagesContext'
|
||||
import { clientLanguages, type ClientLanguageCode } from '@/languages/lib/client-languages'
|
||||
import { languages, type LanguageCode } from '@/languages/lib/languages'
|
||||
import { MainContextProvider } from '@/app/components/MainContextProvider'
|
||||
import { createMinimalMainContext } from '@/app/lib/main-context-adapter'
|
||||
import type { AppRouterContext } from '@/app/lib/app-router-context'
|
||||
@@ -31,16 +31,11 @@ interface ClientLayoutProps {
|
||||
|
||||
export function ClientLayout({ children, appContext, pageData }: ClientLayoutProps): JSX.Element {
|
||||
const { theme } = useTheme()
|
||||
const locale: ClientLanguageCode = useDetectLocale()
|
||||
const locale: LanguageCode = useDetectLocale()
|
||||
const [isInitialized, setIsInitialized] = useState(false)
|
||||
const [initializationError, setInitializationError] = useState<Error | null>(null)
|
||||
|
||||
const languagesContext: LanguagesContextT = useMemo(
|
||||
() => ({
|
||||
languages: clientLanguages,
|
||||
}),
|
||||
[],
|
||||
)
|
||||
const languagesContext: LanguagesContextT = useMemo(() => ({ languages }), [])
|
||||
|
||||
// Create MainContext-compatible data for App Router
|
||||
const mainContext = useMemo(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { createContext, useContext } from 'react'
|
||||
import { clientLanguages, type ClientLanguageCode } from '@/languages/lib/client-languages'
|
||||
import { languages, type LanguageCode } from '@/languages/lib/languages'
|
||||
|
||||
export type AppRouterLanguageItem = {
|
||||
name: string
|
||||
@@ -12,7 +12,7 @@ export type AppRouterLanguageItem = {
|
||||
|
||||
export type AppRouterLanguagesContextT = {
|
||||
languages: Record<string, AppRouterLanguageItem>
|
||||
currentLanguage?: ClientLanguageCode
|
||||
currentLanguage?: LanguageCode
|
||||
}
|
||||
|
||||
export const AppRouterLanguagesContext = createContext<AppRouterLanguagesContextT | null>(null)
|
||||
@@ -34,7 +34,7 @@ export const useAppRouterLanguages = (): AppRouterLanguagesContextT => {
|
||||
*/
|
||||
interface AppRouterLanguagesProviderProps {
|
||||
children: React.ReactNode
|
||||
currentLanguage?: ClientLanguageCode
|
||||
currentLanguage?: LanguageCode
|
||||
}
|
||||
|
||||
export function AppRouterLanguagesProvider({
|
||||
@@ -42,7 +42,7 @@ export function AppRouterLanguagesProvider({
|
||||
currentLanguage,
|
||||
}: AppRouterLanguagesProviderProps) {
|
||||
const value: AppRouterLanguagesContextT = {
|
||||
languages: clientLanguages,
|
||||
languages,
|
||||
currentLanguage,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { getUIDataMerged } from '@/data-directory/lib/get-data'
|
||||
import { createTranslationFunctions } from '@/languages/lib/translation-utils'
|
||||
import { LinkExternalIcon } from '@primer/octicons-react'
|
||||
import type { ClientLanguageCode } from '@/languages/lib/client-languages'
|
||||
import type { LanguageCode } from '@/languages/lib/languages'
|
||||
|
||||
interface ServerFooterProps {
|
||||
currentLanguage: ClientLanguageCode
|
||||
currentLanguage: LanguageCode
|
||||
}
|
||||
|
||||
export function ServerFooter({ currentLanguage }: ServerFooterProps) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { getUIDataMerged } from '@/data-directory/lib/get-data'
|
||||
import { type ClientLanguageCode } from '@/languages/lib/client-languages'
|
||||
import { type LanguageCode } from '@/languages/lib/languages'
|
||||
import { translate } from '@/languages/lib/translation-utils'
|
||||
import { extractLanguageFromPath } from '@/app/lib/language-utils'
|
||||
|
||||
export interface AppRouterContext {
|
||||
currentLanguage: ClientLanguageCode
|
||||
currentLanguage: LanguageCode
|
||||
currentVersion: string
|
||||
sitename: string
|
||||
site: {
|
||||
@@ -19,7 +19,7 @@ export interface AppRouterContext {
|
||||
*/
|
||||
export function createAppRouterContext(
|
||||
pathname: string = '/',
|
||||
fallbackLanguage?: ClientLanguageCode,
|
||||
fallbackLanguage?: LanguageCode,
|
||||
): AppRouterContext {
|
||||
let language = extractLanguageFromPath(pathname)
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { clientLanguageKeys, type ClientLanguageCode } from '@/languages/lib/client-languages'
|
||||
import { languageKeys, type LanguageCode } from '@/languages/lib/languages'
|
||||
|
||||
/**
|
||||
* Extract language from URL path
|
||||
* Handles paths like /en/something, /es/articles, etc.
|
||||
*/
|
||||
export function extractLanguageFromPath(path: string): ClientLanguageCode {
|
||||
export function extractLanguageFromPath(path: string): LanguageCode {
|
||||
try {
|
||||
const pathSegments = path.split('/')
|
||||
const firstSegment = pathSegments[1]
|
||||
|
||||
if (firstSegment && clientLanguageKeys.includes(firstSegment)) {
|
||||
return firstSegment as ClientLanguageCode
|
||||
if (firstSegment && languageKeys.includes(firstSegment)) {
|
||||
return firstSegment as LanguageCode
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to extract language from path:', error)
|
||||
@@ -24,7 +24,7 @@ export function extractLanguageFromPath(path: string): ClientLanguageCode {
|
||||
export function hasLanguagePrefix(path: string): boolean {
|
||||
const pathSegments = path.split('/')
|
||||
const firstSegment = pathSegments[1]
|
||||
return Boolean(firstSegment && clientLanguageKeys.includes(firstSegment))
|
||||
return Boolean(firstSegment && languageKeys.includes(firstSegment))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +43,7 @@ export function stripLanguagePrefix(path: string): string {
|
||||
* Add language prefix to path if it doesn't have one
|
||||
* e.g., /articles/example + 'es' -> /es/articles/example
|
||||
*/
|
||||
export function addLanguagePrefix(path: string, language: ClientLanguageCode): string {
|
||||
export function addLanguagePrefix(path: string, language: LanguageCode): string {
|
||||
if (hasLanguagePrefix(path)) {
|
||||
return path
|
||||
}
|
||||
|
||||
@@ -1,55 +1,51 @@
|
||||
'use client'
|
||||
|
||||
import { createContext, useContext, ReactNode, useMemo } from 'react'
|
||||
import {
|
||||
clientLanguages,
|
||||
clientLanguageKeys,
|
||||
type ClientLanguageCode,
|
||||
} from '@/languages/lib/client-languages'
|
||||
import { languages, languageKeys, type LanguageCode } from '@/languages/lib/languages'
|
||||
|
||||
interface LocaleContextType {
|
||||
readonly locale: ClientLanguageCode
|
||||
readonly isValidLocale: (locale: string) => locale is ClientLanguageCode
|
||||
readonly getSupportedLocales: () => readonly ClientLanguageCode[]
|
||||
readonly getLocaleDisplayName: (locale: ClientLanguageCode) => string
|
||||
readonly getLocaleNativeName: (locale: ClientLanguageCode) => string
|
||||
readonly locale: LanguageCode
|
||||
readonly isValidLocale: (locale: string) => locale is LanguageCode
|
||||
readonly getSupportedLocales: () => readonly LanguageCode[]
|
||||
readonly getLocaleDisplayName: (locale: LanguageCode) => string
|
||||
readonly getLocaleNativeName: (locale: LanguageCode) => string
|
||||
}
|
||||
|
||||
const LocaleContext = createContext<LocaleContextType | null>(null)
|
||||
|
||||
interface LocaleProviderProps {
|
||||
readonly children: ReactNode
|
||||
readonly locale: ClientLanguageCode
|
||||
readonly locale: LanguageCode
|
||||
}
|
||||
|
||||
// Use client languages as the source of truth for supported locales
|
||||
const SUPPORTED_LOCALES: readonly ClientLanguageCode[] = clientLanguageKeys as ClientLanguageCode[]
|
||||
const SUPPORTED_LOCALES: readonly LanguageCode[] = languageKeys as LanguageCode[]
|
||||
|
||||
/**
|
||||
* Validates if a string is a supported locale
|
||||
*/
|
||||
function isValidLocale(locale: string): locale is ClientLanguageCode {
|
||||
return clientLanguageKeys.includes(locale)
|
||||
function isValidLocale(locale: string): locale is LanguageCode {
|
||||
return languageKeys.includes(locale)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets display name for a locale from client languages data
|
||||
* Gets display name for a locale from languages module
|
||||
*/
|
||||
function getLocaleDisplayName(locale: ClientLanguageCode): string {
|
||||
return clientLanguages[locale]?.name || locale
|
||||
function getLocaleDisplayName(locale: LanguageCode): string {
|
||||
return languages[locale]?.name || locale
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets native name for a locale from client languages data
|
||||
* Gets native name for a locale from languages module
|
||||
*/
|
||||
function getLocaleNativeName(locale: ClientLanguageCode): string {
|
||||
return clientLanguages[locale]?.nativeName || clientLanguages[locale]?.name || locale
|
||||
function getLocaleNativeName(locale: LanguageCode): string {
|
||||
return languages[locale]?.nativeName || languages[locale]?.name || locale
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets browser language preference as a valid locale
|
||||
*/
|
||||
function getBrowserLocale(): ClientLanguageCode {
|
||||
function getBrowserLocale(): LanguageCode {
|
||||
if (typeof window === 'undefined') return 'en'
|
||||
|
||||
const browserLang = window.navigator.language.split('-')[0]
|
||||
@@ -77,7 +73,7 @@ export function LocaleProvider({ children, locale }: LocaleProviderProps): JSX.E
|
||||
/**
|
||||
* Hook to get current locale with enhanced error handling
|
||||
*/
|
||||
export function useLocale(): ClientLanguageCode {
|
||||
export function useLocale(): LanguageCode {
|
||||
const context = useContext(LocaleContext)
|
||||
|
||||
if (context) {
|
||||
@@ -118,4 +114,4 @@ export function useLocaleContext(): LocaleContextType {
|
||||
}
|
||||
|
||||
export { isValidLocale, getLocaleDisplayName, getLocaleNativeName }
|
||||
export type { LocaleContextType, ClientLanguageCode }
|
||||
export type { LocaleContextType, LanguageCode }
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { extractLanguageFromPath } from '@/app/lib/language-utils'
|
||||
import { extractVersionFromPath } from '@/app/lib/version-utils'
|
||||
import { getUIDataMerged } from '@/data-directory/lib/get-data'
|
||||
import { type ClientLanguageCode } from '@/languages/lib/client-languages'
|
||||
import { type LanguageCode } from '@/languages/lib/languages'
|
||||
import { createTranslationFunctions, translate } from '@/languages/lib/translation-utils'
|
||||
|
||||
export interface ServerAppRouterContext {
|
||||
currentLanguage: ClientLanguageCode
|
||||
currentLanguage: LanguageCode
|
||||
currentVersion: string
|
||||
sitename: string
|
||||
site: { data: { ui: any } }
|
||||
@@ -33,7 +33,7 @@ export function createServerAppRouterContext(pathname: string): ServerAppRouterC
|
||||
/**
|
||||
* Create server-side footer with translations
|
||||
*/
|
||||
export function createServerFooterContent(language: ClientLanguageCode) {
|
||||
export function createServerFooterContent(language: LanguageCode) {
|
||||
const uiData = getUIDataMerged(language)
|
||||
const { t } = createTranslationFunctions(uiData, 'footer')
|
||||
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { useMemo, useEffect, useState } from 'react'
|
||||
import { clientLanguageKeys, type ClientLanguageCode } from '@/languages/lib/client-languages'
|
||||
import { languageKeys, type LanguageCode } from '@/languages/lib/languages'
|
||||
import Cookies from '@/frame/components/lib/cookies'
|
||||
import { USER_LANGUAGE_COOKIE_NAME } from '@/frame/lib/constants'
|
||||
|
||||
/**
|
||||
* Validates if a string is a supported locale using client languages
|
||||
*/
|
||||
function isValidLocale(locale: string): locale is ClientLanguageCode {
|
||||
return clientLanguageKeys.includes(locale)
|
||||
function isValidLocale(locale: string): locale is LanguageCode {
|
||||
return languageKeys.includes(locale)
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to detect locale from various sources with fallback logic
|
||||
*/
|
||||
export function useDetectLocale(): ClientLanguageCode {
|
||||
export function useDetectLocale(): LanguageCode {
|
||||
const pathname = usePathname()
|
||||
const [cookieLanguage, setCookieLanguage] = useState<ClientLanguageCode | null>(null)
|
||||
const [browserLanguage, setBrowserLanguage] = useState<ClientLanguageCode | null>(null)
|
||||
const [cookieLanguage, setCookieLanguage] = useState<LanguageCode | null>(null)
|
||||
const [browserLanguage, setBrowserLanguage] = useState<LanguageCode | null>(null)
|
||||
|
||||
// Read cookie and browser language on client-side mount
|
||||
useEffect(() => {
|
||||
@@ -71,7 +71,7 @@ export function useDetectLocale(): ClientLanguageCode {
|
||||
/**
|
||||
* Utility function to detect locale from pathname (for server-side use)
|
||||
*/
|
||||
export function detectLocaleFromPath(pathname: string): ClientLanguageCode {
|
||||
export function detectLocaleFromPath(pathname: string): LanguageCode {
|
||||
const pathSegments = pathname.split('/')
|
||||
const firstSegment = pathSegments[1]
|
||||
|
||||
@@ -82,8 +82,8 @@ export function detectLocaleFromPath(pathname: string): ClientLanguageCode {
|
||||
return 'en'
|
||||
}
|
||||
|
||||
export function getSupportedLocales(): readonly ClientLanguageCode[] {
|
||||
return clientLanguageKeys as ClientLanguageCode[]
|
||||
export function getSupportedLocales(): readonly LanguageCode[] {
|
||||
return languageKeys as LanguageCode[]
|
||||
}
|
||||
|
||||
export { isValidLocale }
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
* Enhanced type definitions for the app router with strict validation
|
||||
*/
|
||||
|
||||
import type { ClientLanguageCode } from '@/languages/lib/client-languages'
|
||||
import type { LanguageCode } from '@/languages/lib/languages'
|
||||
|
||||
// Core theme types with strict validation
|
||||
export type Theme = 'light' | 'dark' | 'auto'
|
||||
export type ColorMode = 'light' | 'dark'
|
||||
|
||||
// Re-export locale type from client-languages for consistency
|
||||
export type Locale = ClientLanguageCode
|
||||
// Re-export locale type from languages.ts for consistency
|
||||
export type Locale = LanguageCode
|
||||
|
||||
// Version and product identifiers with validation
|
||||
export type VersionId = string
|
||||
|
||||
@@ -14,7 +14,7 @@ import { isArchivedVersion } from '@/archives/lib/is-archived-version'
|
||||
import { setFastlySurrogateKey, SURROGATE_ENUMS } from '@/frame/middleware/set-fastly-surrogate-key'
|
||||
import { readCompressedJsonFileFallbackLazily } from '@/frame/lib/read-json-file'
|
||||
import { archivedCacheControl, languageCacheControl } from '@/frame/middleware/cache-control'
|
||||
import { pathLanguagePrefixed, languagePrefixPathRegex } from '@/languages/lib/languages'
|
||||
import { pathLanguagePrefixed, languagePrefixPathRegex } from '@/languages/lib/languages-server'
|
||||
import getRedirect, { splitPathByLanguage } from '@/redirects/lib/get-redirect'
|
||||
import getRemoteJSON from '@/frame/lib/get-remote-json'
|
||||
import { ExtendedRequest } from '@/types'
|
||||
|
||||
@@ -30,7 +30,7 @@ import { brotliCompressSync } from 'zlib'
|
||||
import chalk from 'chalk'
|
||||
import { program, Option } from 'commander'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { loadPages, loadUnversionedTree } from '@/frame/lib/page-data'
|
||||
import { CACHE_FILE_PATH, getPageInfo } from '../middleware/article-pageinfo'
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { program } from 'commander'
|
||||
import walk from 'walk-sync'
|
||||
|
||||
import walkFiles from '@/workflows/walk-files'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
|
||||
const EXCEPTIONS = new Set([
|
||||
'assets/images/site/favicon.ico',
|
||||
|
||||
@@ -7,7 +7,7 @@ import { visitParents } from 'unist-util-visit-parents'
|
||||
import { visit, SKIP } from 'unist-util-visit'
|
||||
import { remove } from 'unist-util-remove'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { MARKDOWN_OPTIONS } from '../../content-linter/lib/helpers/unified-formatter-options'
|
||||
|
||||
interface Config {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { filterTokens } from 'markdownlint-rule-helpers'
|
||||
|
||||
import { addFixErrorDetail, getRange } from '../helpers/utils'
|
||||
import { allLanguageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import type { RuleParams, RuleErrorCallback, Rule } from '../../types'
|
||||
|
||||
export const internalLinksNoLang: Rule = {
|
||||
@@ -28,7 +28,7 @@ export const internalLinksNoLang: Rule = {
|
||||
.filter((attr: [string, string]) => attr[1].startsWith('/') || !attr[1].startsWith('//'))
|
||||
// Filter out link paths that start with language code
|
||||
.filter((attr: [string, string]) =>
|
||||
allLanguageKeys.some((lang) => attr[1].split('/')[1] === lang),
|
||||
languageKeys.some((lang) => attr[1].split('/')[1] === lang),
|
||||
)
|
||||
// Get the link path from the attribute
|
||||
.map((attr: [string, string]) => attr[1])
|
||||
|
||||
@@ -15,7 +15,7 @@ import { defaultConfig } from '../lib/default-markdownlint-options'
|
||||
import { prettyPrintResults } from './pretty-print-results'
|
||||
import { getLintableYml } from '@/content-linter/lib/helpers/get-lintable-yml'
|
||||
import { printAnnotationResults } from '../lib/helpers/print-annotations'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { shouldIncludeResult } from '../lib/helpers/should-include-result'
|
||||
|
||||
program
|
||||
|
||||
@@ -9,7 +9,7 @@ import walk from 'walk-sync'
|
||||
import { zip } from 'lodash-es'
|
||||
import { beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { getDiffFiles } from '../lib/diff-files'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
@@ -43,7 +43,7 @@ import { writeFileSync, statSync } from 'fs'
|
||||
|
||||
import { program, Option } from 'commander'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { allVersions } from '@/versions/lib/all-versions'
|
||||
import { allDocuments, POSSIBLE_FIELDS, type AllDocument } from './lib'
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import Page from '@/frame/lib/page'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-version'
|
||||
import { DataDirectory } from '@/tests/helpers/data-directory'
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { liquid } from '@/content-render/index'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { DataDirectory } from '@/tests/helpers/data-directory'
|
||||
|
||||
describe('liquid helper tags', () => {
|
||||
|
||||
@@ -5,7 +5,7 @@ import yaml from 'js-yaml'
|
||||
import matter from '@gr2m/gray-matter'
|
||||
import { merge, get } from 'lodash-es'
|
||||
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { correctTranslatedContentStrings } from '@/languages/lib/correct-translation-content'
|
||||
|
||||
interface YAMLException extends Error {
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import chalk from 'chalk'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
|
||||
type Options = {
|
||||
verbose?: boolean
|
||||
|
||||
@@ -38,7 +38,7 @@ import type { Page } from '@/types'
|
||||
import warmServer from '@/frame/lib/warm-server'
|
||||
import { getDeepDataByLanguage } from '@/data-directory/lib/get-data'
|
||||
import { getLiquidTokens } from '@/content-linter/lib/helpers/liquid-utils'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { correctTranslatedContentStrings } from '@/languages/lib/correct-translation-content'
|
||||
|
||||
const EXCEPTIONS = new Set([
|
||||
|
||||
@@ -3,7 +3,7 @@ import path from 'path'
|
||||
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import {
|
||||
getDataByLanguage,
|
||||
getDeepDataByLanguage,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { expect, test, vi } from 'vitest'
|
||||
import { get, getDOM } from '@/tests/helpers/e2etest'
|
||||
|
||||
import { describeIfDocsEarlyAccess } from '@/tests/helpers/conditional-runs'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
|
||||
const VALID_EARLY_ACCESS_URI = '/early-access/github/save-time-with-slash-commands'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { allVersionKeys } from '@/versions/lib/all-versions'
|
||||
import { productIds } from '@/products/lib/all-products'
|
||||
import { allTools } from '@/tools/lib/all-tools'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import path from 'path'
|
||||
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import type { Language } from '@/languages/lib/languages'
|
||||
import type { UnversionedTree, UnversionLanguageTree, SiteTree, Tree } from '@/types'
|
||||
|
||||
import languages from '@/languages/lib/languages'
|
||||
import { allVersions } from '@/versions/lib/all-versions'
|
||||
import createTree from './create-tree'
|
||||
import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-version'
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { NextFunction, Response } from 'express'
|
||||
|
||||
import type { ExtendedRequest, Context } from '@/types'
|
||||
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import enterpriseServerReleases from '@/versions/lib/enterprise-server-releases'
|
||||
import { allVersions } from '@/versions/lib/all-versions'
|
||||
import { productMap } from '@/products/lib/all-products'
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Response, NextFunction } from 'express'
|
||||
import type { ExtendedRequest } from '@/types'
|
||||
import { getProductGroups } from '@/products/lib/get-product-groups'
|
||||
import warmServer from '@/frame/lib/warm-server'
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { allVersionKeys } from '@/versions/lib/all-versions'
|
||||
|
||||
const isHomepage = (path: string) => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { Response, NextFunction } from 'express'
|
||||
|
||||
import { ROOT } from '@/frame/lib/constants'
|
||||
import Page from '@/frame/lib/page'
|
||||
import { languagePrefixPathRegex } from '@/languages/lib/languages'
|
||||
import { languagePrefixPathRegex } from '@/languages/lib/languages-server'
|
||||
import type { ExtendedRequest } from '@/types'
|
||||
|
||||
interface FindPageOptions {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { shouldUseAppRouter, isVersionedPath } from '@/app/lib/routing-patterns'
|
||||
import { isArchivedVersion } from '@/archives/lib/is-archived-version'
|
||||
import { languagePrefixPathRegex } from '@/languages/lib/languages'
|
||||
import { languagePrefixPathRegex } from '@/languages/lib/languages-server'
|
||||
import versionSatisfiesRange from '@/versions/lib/version-satisfies-range'
|
||||
import type { NextFunction, Request, Response } from 'express'
|
||||
import helmet from 'helmet'
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { ExtendedRequest } from '@/types'
|
||||
import { defaultCacheControl } from '@/frame/middleware/cache-control'
|
||||
import catchMiddlewareError from '@/observability/middleware/catch-middleware-error'
|
||||
import statsd from '@/observability/lib/statsd'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { allVersions } from '@/versions/lib/all-versions'
|
||||
|
||||
const router = express.Router()
|
||||
|
||||
@@ -19,7 +19,7 @@ import path from 'path'
|
||||
import type { Response, NextFunction } from 'express'
|
||||
|
||||
import type { ExtendedRequest, UnversionedTree, SiteTree } from '@/types'
|
||||
import languages, { languageKeys } from '@/languages/lib/languages'
|
||||
import languages, { languageKeys } from '@/languages/lib/languages-server'
|
||||
import createTree from '@/frame/lib/create-tree'
|
||||
import warmServer from '@/frame/lib/warm-server'
|
||||
import { loadSiteTree, loadPages, loadPageMap } from '@/frame/lib/page-data'
|
||||
|
||||
@@ -6,7 +6,7 @@ import { decode } from 'html-entities'
|
||||
import { chain, pick } from 'lodash-es'
|
||||
|
||||
import { loadPages } from '@/frame/lib/page-data'
|
||||
import libLanguages from '@/languages/lib/languages'
|
||||
import libLanguages from '@/languages/lib/languages-server'
|
||||
import { liquid } from '@/content-render/index'
|
||||
import patterns from '@/frame/lib/patterns'
|
||||
import removeFPTFromPath from '@/versions/lib/remove-fpt-from-path'
|
||||
|
||||
@@ -17,7 +17,7 @@ import createApp from '@/frame/lib/app'
|
||||
import EnterpriseServerReleases from '@/versions/lib/enterprise-server-releases'
|
||||
import loadRedirects from '@/redirects/lib/precompile'
|
||||
import { loadPageMap, loadPages } from '@/frame/lib/page-data'
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { RewriteAssetPathsPlugin } from '@/ghes-releases/scripts/deprecate/rewrite-asset-paths'
|
||||
import Page from '@/frame/lib/page'
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
readCompressedJsonFileFallback,
|
||||
} from '@/frame/lib/read-json-file'
|
||||
import { getAutomatedPageMiniTocItems } from '@/frame/lib/get-mini-toc-items'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { allVersions } from '@/versions/lib/all-versions'
|
||||
interface GraphqlContext {
|
||||
currentLanguage: string
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
import type { LanguageItem } from '@/languages/components/LanguagesContext'
|
||||
|
||||
/**
|
||||
* Client-safe language data extracted from src/languages/lib/languages.ts.
|
||||
* Only used by frontend components.
|
||||
* Does not include server-side logic or Node.js-specific fs or path operations.
|
||||
*/
|
||||
export const clientLanguages: Record<string, LanguageItem> = {
|
||||
en: {
|
||||
name: 'English',
|
||||
code: 'en',
|
||||
nativeName: 'English',
|
||||
hreflang: 'en',
|
||||
},
|
||||
es: {
|
||||
name: 'Spanish',
|
||||
code: 'es',
|
||||
nativeName: 'Español',
|
||||
hreflang: 'es',
|
||||
},
|
||||
ja: {
|
||||
name: 'Japanese',
|
||||
code: 'ja',
|
||||
nativeName: '日本語',
|
||||
hreflang: 'ja',
|
||||
},
|
||||
pt: {
|
||||
name: 'Portuguese',
|
||||
code: 'pt',
|
||||
nativeName: 'Português do Brasil',
|
||||
hreflang: 'pt',
|
||||
},
|
||||
zh: {
|
||||
name: 'Simplified Chinese',
|
||||
code: 'zh',
|
||||
nativeName: '简体中文',
|
||||
hreflang: 'zh-Hans',
|
||||
},
|
||||
ru: {
|
||||
name: 'Russian',
|
||||
code: 'ru',
|
||||
nativeName: 'Русский',
|
||||
hreflang: 'ru',
|
||||
},
|
||||
fr: {
|
||||
name: 'French',
|
||||
code: 'fr',
|
||||
nativeName: 'Français',
|
||||
hreflang: 'fr',
|
||||
},
|
||||
ko: {
|
||||
name: 'Korean',
|
||||
code: 'ko',
|
||||
nativeName: '한국어',
|
||||
hreflang: 'ko',
|
||||
},
|
||||
de: {
|
||||
name: 'German',
|
||||
code: 'de',
|
||||
nativeName: 'Deutsch',
|
||||
hreflang: 'de',
|
||||
},
|
||||
}
|
||||
|
||||
export const clientLanguageKeys: string[] = Object.keys(clientLanguages)
|
||||
|
||||
export type ClientLanguageCode = keyof typeof clientLanguages
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import yaml from 'js-yaml'
|
||||
import languages from './languages'
|
||||
import languages from './languages-server'
|
||||
|
||||
const cache: Record<string, any> = {}
|
||||
|
||||
|
||||
97
src/languages/lib/languages-server.ts
Normal file
97
src/languages/lib/languages-server.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
This file adds the following properties to languages in ./languages.ts:
|
||||
- dir: string
|
||||
|
||||
This file will also remove languages for local development and tests
|
||||
that have not be specified by ENABLED_LANGUAGES
|
||||
*/
|
||||
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import dotenv from 'dotenv'
|
||||
|
||||
import { ROOT, TRANSLATIONS_ROOT, TRANSLATIONS_FIXTURE_ROOT } from '@/frame/lib/constants'
|
||||
import { languages as baseLanguages, type Language as BaseLanguage } from './languages'
|
||||
|
||||
dotenv.config({ quiet: true })
|
||||
|
||||
// Server-side language extends base language with required dir property
|
||||
export interface Language extends BaseLanguage {
|
||||
dir: string
|
||||
}
|
||||
|
||||
export interface Languages {
|
||||
[code: string]: Language
|
||||
}
|
||||
|
||||
function getRoot(languageCode: string): string {
|
||||
if (languageCode === 'en') return ROOT
|
||||
|
||||
// This one trumps anything else. This makes it possible, and convenient,
|
||||
// for running tests that depends on testing translations based on
|
||||
// fixtures exclusively.
|
||||
if (TRANSLATIONS_FIXTURE_ROOT) {
|
||||
return path.join(TRANSLATIONS_FIXTURE_ROOT, languageCode)
|
||||
}
|
||||
|
||||
// example: process.env.TRANSLATIONS_ROOT_ES_ES
|
||||
const possibleEnvVar =
|
||||
process.env[`TRANSLATIONS_ROOT_${languageCode.toUpperCase().replace(/-/g, '_')}`]
|
||||
if (possibleEnvVar) {
|
||||
return possibleEnvVar
|
||||
}
|
||||
|
||||
// Default
|
||||
return path.join(TRANSLATIONS_ROOT, languageCode)
|
||||
}
|
||||
|
||||
// Build server languages with directory paths
|
||||
const allLanguagesWithDirs: Languages = {}
|
||||
for (const [code, lang] of Object.entries(baseLanguages)) {
|
||||
allLanguagesWithDirs[code] = {
|
||||
...lang,
|
||||
dir: getRoot(lang.locale || code),
|
||||
}
|
||||
}
|
||||
|
||||
Object.freeze(allLanguagesWithDirs)
|
||||
|
||||
const languages: Languages = { ...allLanguagesWithDirs }
|
||||
|
||||
if (TRANSLATIONS_FIXTURE_ROOT) {
|
||||
// Keep all languages that have a directory in the fixture root.
|
||||
Object.entries(languages).forEach(([code, { dir }]) => {
|
||||
if (code !== 'en' && !fs.existsSync(dir)) {
|
||||
delete languages[code]
|
||||
}
|
||||
})
|
||||
} else if (process.env.ENABLED_LANGUAGES) {
|
||||
if (process.env.ENABLED_LANGUAGES.toLowerCase() !== 'all') {
|
||||
Object.keys(languages).forEach((code) => {
|
||||
if (!process.env.ENABLED_LANGUAGES!.includes(code)) {
|
||||
delete languages[code]
|
||||
}
|
||||
})
|
||||
// This makes the translation health report not valid JSON
|
||||
// console.log(`ENABLED_LANGUAGES: ${process.env.ENABLED_LANGUAGES}`)
|
||||
}
|
||||
} else if (process.env.NODE_ENV === 'test') {
|
||||
// Unless explicitly set, when running tests default to just English
|
||||
Object.keys(languages).forEach((code) => {
|
||||
if (code !== 'en') delete languages[code]
|
||||
})
|
||||
}
|
||||
|
||||
export const languageKeys: string[] = Object.keys(languages)
|
||||
|
||||
export const languagePrefixPathRegex: RegExp = new RegExp(`^/(${languageKeys.join('|')})(/|$)`)
|
||||
|
||||
/** Return true if the URL is something like /en/foo or /ja but return false
|
||||
* if it's something like /foo or /foo/bar or /fr (because French (fr)
|
||||
* is currently not an active language)
|
||||
*/
|
||||
export function pathLanguagePrefixed(path: string): boolean {
|
||||
return languagePrefixPathRegex.test(path)
|
||||
}
|
||||
|
||||
export default languages
|
||||
@@ -1,26 +1,15 @@
|
||||
// See also languages-schema.ts
|
||||
// Nota bene: If you are adding a new language,
|
||||
// change accept-language handling in CDN config as well.
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
|
||||
import dotenv from 'dotenv'
|
||||
|
||||
import { ROOT, TRANSLATIONS_ROOT, TRANSLATIONS_FIXTURE_ROOT } from '@/frame/lib/constants'
|
||||
|
||||
dotenv.config({ quiet: true })
|
||||
|
||||
export interface Language {
|
||||
name: string
|
||||
nativeName?: string
|
||||
code: string
|
||||
hreflang: string
|
||||
redirectPatterns?: RegExp[]
|
||||
dir: string
|
||||
}
|
||||
/**
|
||||
* Client-safe language definitions without server-side dependencies.
|
||||
* For server-side usage with fs/path operations, import from './languages-server.ts'
|
||||
*/
|
||||
|
||||
export type LanguageCode = 'en' | 'es' | 'ja' | 'pt' | 'zh' | 'ru' | 'fr' | 'ko' | 'de'
|
||||
export type LocaleCode =
|
||||
| 'en'
|
||||
| 'es-es'
|
||||
| 'ja-jp'
|
||||
| 'pt-br'
|
||||
@@ -30,57 +19,35 @@ export type LocaleCode =
|
||||
| 'ko-kr'
|
||||
| 'de-de'
|
||||
|
||||
export interface Language {
|
||||
name: string
|
||||
nativeName?: string
|
||||
code: LanguageCode
|
||||
hreflang: string
|
||||
locale: LocaleCode
|
||||
redirectPatterns?: RegExp[]
|
||||
dir?: string
|
||||
}
|
||||
|
||||
export interface Languages {
|
||||
[code: string]: Language
|
||||
}
|
||||
|
||||
const possibleEnvVars: Record<LocaleCode, string | undefined> = {
|
||||
'es-es': process.env.TRANSLATIONS_ROOT_ES_ES,
|
||||
'ja-jp': process.env.TRANSLATIONS_ROOT_JA_JP,
|
||||
'pt-br': process.env.TRANSLATIONS_ROOT_PT_BR,
|
||||
'zh-cn': process.env.TRANSLATIONS_ROOT_ZH_CN,
|
||||
'ru-ru': process.env.TRANSLATIONS_ROOT_RU_RU,
|
||||
'fr-fr': process.env.TRANSLATIONS_ROOT_FR_FR,
|
||||
'ko-kr': process.env.TRANSLATIONS_ROOT_KO_KR,
|
||||
'de-de': process.env.TRANSLATIONS_ROOT_DE_DE,
|
||||
}
|
||||
|
||||
function getRoot(languageCode: string): string {
|
||||
if (languageCode === 'en') return ROOT
|
||||
|
||||
// This one trumps anything else. This makes it possible, and convenient,
|
||||
// for running tests that depends on testing translations based on
|
||||
// fixtures exclusively.
|
||||
if (TRANSLATIONS_FIXTURE_ROOT) {
|
||||
return path.join(TRANSLATIONS_FIXTURE_ROOT, languageCode)
|
||||
}
|
||||
|
||||
if (languageCode in possibleEnvVars) {
|
||||
const possibleEnvVar = possibleEnvVars[languageCode as LocaleCode]
|
||||
if (possibleEnvVar) {
|
||||
return possibleEnvVar
|
||||
}
|
||||
} else {
|
||||
console.warn(`Not recognized languageCode '${languageCode}'`)
|
||||
}
|
||||
// Default
|
||||
return path.join(TRANSLATIONS_ROOT, languageCode)
|
||||
}
|
||||
|
||||
// Languages in order of accept-language header frequency
|
||||
const allLanguages: Languages = {
|
||||
// Note: 'dir' is omitted here as it requires server-side path resolution
|
||||
export const languages: Languages = {
|
||||
en: {
|
||||
name: 'English',
|
||||
code: 'en',
|
||||
hreflang: 'en',
|
||||
dir: getRoot('en'),
|
||||
locale: 'en',
|
||||
},
|
||||
es: {
|
||||
name: 'Spanish',
|
||||
nativeName: 'Español',
|
||||
code: 'es',
|
||||
hreflang: 'es',
|
||||
dir: getRoot('es-es'),
|
||||
locale: 'es-es',
|
||||
},
|
||||
ja: {
|
||||
name: 'Japanese',
|
||||
@@ -88,7 +55,7 @@ const allLanguages: Languages = {
|
||||
code: 'ja',
|
||||
hreflang: 'ja',
|
||||
redirectPatterns: [/^\/jp/],
|
||||
dir: getRoot('ja-jp'),
|
||||
locale: 'ja-jp',
|
||||
},
|
||||
pt: {
|
||||
name: 'Portuguese',
|
||||
@@ -96,7 +63,7 @@ const allLanguages: Languages = {
|
||||
code: 'pt',
|
||||
hreflang: 'pt',
|
||||
redirectPatterns: [/^\/br/],
|
||||
dir: getRoot('pt-br'),
|
||||
locale: 'pt-br',
|
||||
},
|
||||
zh: {
|
||||
name: 'Simplified Chinese',
|
||||
@@ -104,21 +71,21 @@ const allLanguages: Languages = {
|
||||
code: 'zh',
|
||||
hreflang: 'zh-Hans',
|
||||
redirectPatterns: [/^\/cn/, /^\/zh-\w{2}/],
|
||||
dir: getRoot('zh-cn'),
|
||||
locale: 'zh-cn',
|
||||
},
|
||||
ru: {
|
||||
name: 'Russian',
|
||||
nativeName: 'Русский',
|
||||
code: 'ru',
|
||||
hreflang: 'ru',
|
||||
dir: getRoot('ru-ru'),
|
||||
locale: 'ru-ru',
|
||||
},
|
||||
fr: {
|
||||
name: 'French',
|
||||
nativeName: 'Français',
|
||||
code: 'fr',
|
||||
hreflang: 'fr',
|
||||
dir: getRoot('fr-fr'),
|
||||
locale: 'fr-fr',
|
||||
},
|
||||
ko: {
|
||||
name: 'Korean',
|
||||
@@ -126,59 +93,16 @@ const allLanguages: Languages = {
|
||||
code: 'ko',
|
||||
hreflang: 'ko',
|
||||
redirectPatterns: [/^\/kr/],
|
||||
dir: getRoot('ko-kr'),
|
||||
locale: 'ko-kr',
|
||||
},
|
||||
de: {
|
||||
name: 'German',
|
||||
nativeName: 'Deutsch',
|
||||
code: 'de',
|
||||
hreflang: 'de',
|
||||
dir: getRoot('de-de'),
|
||||
locale: 'de-de',
|
||||
},
|
||||
}
|
||||
|
||||
// Some markdownlint tests depend on having access to all
|
||||
// language keys. Not modifying the original object makes
|
||||
// it possible to export all keys, even when those directories
|
||||
// don't exist on disk.
|
||||
Object.freeze(allLanguages)
|
||||
export const allLanguageKeys: string[] = Object.keys(allLanguages)
|
||||
const languages: Languages = { ...allLanguages }
|
||||
|
||||
if (TRANSLATIONS_FIXTURE_ROOT) {
|
||||
// Keep all languages that have a directory in the fixture root.
|
||||
Object.entries(languages).forEach(([code, { dir }]) => {
|
||||
if (code !== 'en' && !fs.existsSync(dir)) {
|
||||
delete languages[code]
|
||||
}
|
||||
})
|
||||
} else if (process.env.ENABLED_LANGUAGES) {
|
||||
if (process.env.ENABLED_LANGUAGES.toLowerCase() !== 'all') {
|
||||
Object.keys(languages).forEach((code) => {
|
||||
if (!process.env.ENABLED_LANGUAGES!.includes(code)) {
|
||||
delete languages[code]
|
||||
}
|
||||
})
|
||||
// This makes the translation health report not valid JSON
|
||||
// console.log(`ENABLED_LANGUAGES: ${process.env.ENABLED_LANGUAGES}`)
|
||||
}
|
||||
} else if (process.env.NODE_ENV === 'test') {
|
||||
// Unless explicitly set, when running tests default to just English
|
||||
Object.keys(languages).forEach((code) => {
|
||||
if (code !== 'en') delete languages[code]
|
||||
})
|
||||
}
|
||||
|
||||
Object.freeze(languages)
|
||||
export const languageKeys: string[] = Object.keys(languages)
|
||||
|
||||
export const languagePrefixPathRegex: RegExp = new RegExp(`^/(${languageKeys.join('|')})(/|$)`)
|
||||
|
||||
/** Return true if the URL is something like /en/foo or /ja but return false
|
||||
* if it's something like /foo or /foo/bar or /fr (because French (fr)
|
||||
* is currently not an active language)
|
||||
*/
|
||||
export function pathLanguagePrefixed(path: string): boolean {
|
||||
return languagePrefixPathRegex.test(path)
|
||||
}
|
||||
|
||||
export default languages
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Request, Response, NextFunction } from 'express'
|
||||
import parser from 'accept-language-parser'
|
||||
import type { Language as parserLanguage } from 'accept-language-parser'
|
||||
|
||||
import languages, { languageKeys } from '@/languages/lib/languages'
|
||||
import languages, { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { USER_LANGUAGE_COOKIE_NAME } from '@/frame/lib/constants'
|
||||
import type { ExtendedRequest, Languages } from '@/types'
|
||||
import { updateLoggerContext } from '@/observability/logger/lib/logger-context'
|
||||
|
||||
@@ -7,7 +7,7 @@ import { TokenizationError } from 'liquidjs'
|
||||
import walk from 'walk-sync'
|
||||
|
||||
import { getLiquidTokens } from '@/content-linter/lib/helpers/liquid-utils'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import warmServer from '@/frame/lib/warm-server'
|
||||
import type { Site } from '@/types'
|
||||
import { correctTranslatedContentStrings } from '@/languages/lib/correct-translation-content'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
|
||||
import { makeLanguageSurrogateKey } from '@/frame/middleware/set-fastly-surrogate-key'
|
||||
import purgeEdgeCache from '@/workflows/purge-edge-cache'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
describe('files', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test, vi } from 'vitest'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { blockIndex } from '@/frame/middleware/block-robots'
|
||||
import { get, getDOMCached as getDOM } from '@/tests/helpers/e2etest'
|
||||
import Page from '@/frame/lib/page'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { getDOM } from '@/tests/helpers/e2etest'
|
||||
|
||||
const langs = languageKeys.filter((lang) => lang !== 'en')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import { get } from '@/tests/helpers/e2etest'
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
|
||||
const langs = languageKeys.filter((lang) => lang !== 'en')
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { get } from '@/tests/helpers/e2etest'
|
||||
import { USER_LANGUAGE_COOKIE_NAME } from '@/frame/lib/constants'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { get } from '@/tests/helpers/e2etest'
|
||||
|
||||
const langs = languageKeys.filter((lang) => lang !== 'en')
|
||||
|
||||
@@ -6,7 +6,7 @@ import { productMap, data } from '@/products/lib/all-products'
|
||||
import { renderContentWithFallback } from '@/languages/lib/render-with-fallback'
|
||||
import removeFPTFromPath from '@/versions/lib/remove-fpt-from-path'
|
||||
import frontmatter from '@/frame/lib/read-frontmatter'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
|
||||
type PageMap = Record<string, Page>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-version'
|
||||
import { allVersions } from '@/versions/lib/all-versions'
|
||||
import {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { NextFunction, Response } from 'express'
|
||||
|
||||
import patterns from '@/frame/lib/patterns'
|
||||
import { pathLanguagePrefixed } from '@/languages/lib/languages'
|
||||
import { pathLanguagePrefixed } from '@/languages/lib/languages-server'
|
||||
import { deprecatedWithFunctionalRedirects } from '@/versions/lib/enterprise-server-releases'
|
||||
import getRedirect from '../lib/get-redirect'
|
||||
import { defaultCacheControl, languageCacheControl } from '@/frame/middleware/cache-control'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { NextFunction, Response } from 'express'
|
||||
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { defaultCacheControl } from '@/frame/middleware/cache-control'
|
||||
import { ExtendedRequest } from '@/types'
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from 'path'
|
||||
import { readCompressedJsonFileFallback } from '@/frame/lib/read-json-file'
|
||||
import { getAutomatedPageMiniTocItems } from '@/frame/lib/get-mini-toc-items'
|
||||
import { allVersions, getOpenApiVersion } from '@/versions/lib/all-versions'
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import type { Context } from '@/types'
|
||||
import type { Operation } from '@/rest/components/types'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { utcTimestamp } from '@/search/lib/helpers/time'
|
||||
import { allIndexVersionKeys, versionToIndexVersionMap } from '@/search/lib/elasticsearch-versions'
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
we need to validate and parse the parameters. This file contains the configuration for which parameters
|
||||
to expect based on the type of search request "e.g. general search vs autocomplete search" and how to validate them.
|
||||
*/
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import { allIndexVersionKeys, versionToIndexVersionMap } from '@/search/lib/elasticsearch-versions'
|
||||
import { SearchTypes } from '@/search/types'
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Command, Option } from 'commander'
|
||||
import chalk from 'chalk'
|
||||
import dotenv from 'dotenv'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { allVersions } from '@/versions/lib/all-versions'
|
||||
|
||||
import type { IndicesAnalyzeAnalyzeToken } from '@elastic/elasticsearch/lib/api/types'
|
||||
|
||||
@@ -2,7 +2,7 @@ import { program, Option, Command, InvalidArgumentError } from 'commander'
|
||||
import { errors } from '@elastic/elasticsearch'
|
||||
import dotenv from 'dotenv'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
|
||||
import { indexGeneralSearch } from './lib/index-general-search'
|
||||
import {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Client } from '@elastic/elasticsearch'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import { getElasticSearchIndex } from '@/search/lib/elasticsearch-indexes'
|
||||
import { getElasticsearchClient } from '@/search/lib/helpers/get-client'
|
||||
import {
|
||||
|
||||
@@ -3,7 +3,7 @@ import chalk from 'chalk'
|
||||
import dotenv from 'dotenv'
|
||||
import boxen from 'boxen'
|
||||
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import parsePageSectionsIntoRecords from '@/search/scripts/scrape/lib/parse-page-sections-into-records'
|
||||
import getPopularPages from '@/search/scripts/scrape/lib/popular-pages'
|
||||
import domwaiter from '@/search/scripts/scrape/lib/domwaiter'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import chalk from 'chalk'
|
||||
|
||||
import languages from '@/languages/lib/languages'
|
||||
import languages from '@/languages/lib/languages-server'
|
||||
import buildRecords from '@/search/scripts/scrape/lib/build-records'
|
||||
import findIndexablePages from '@/search/scripts/scrape/lib/find-indexable-pages'
|
||||
import { writeIndexRecords } from '@/search/scripts/scrape/lib/search-index-records'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { existsSync, statSync, readdirSync } from 'fs'
|
||||
import { program, Option } from 'commander'
|
||||
|
||||
import { languageKeys } from '@/languages/lib/languages'
|
||||
import { languageKeys } from '@/languages/lib/languages-server'
|
||||
import scrapeIntoIndexJson from '@/search/scripts/scrape/lib/scrape-into-index-json'
|
||||
import {
|
||||
allIndexVersionOptions,
|
||||
|
||||
13
src/types.ts
13
src/types.ts
@@ -3,6 +3,7 @@ import type { Failbot } from '@github/failbot'
|
||||
|
||||
import type enterpriseServerReleases from '@/versions/lib/enterprise-server-releases.d'
|
||||
import type { ValidOcticon } from '@/landings/types'
|
||||
import type { Language, Languages } from '@/languages/lib/languages-server'
|
||||
import type { MiniTocItem } from '@/frame/lib/get-mini-toc-items'
|
||||
|
||||
// Shared type for resolved article information used across landing pages and carousels
|
||||
@@ -325,16 +326,8 @@ export type SecretScanningData = {
|
||||
isduplicate: boolean
|
||||
}
|
||||
|
||||
type Language = {
|
||||
name: string
|
||||
code: string
|
||||
hreflang: string
|
||||
dir: string
|
||||
}
|
||||
|
||||
export type Languages = {
|
||||
[key: string]: Language
|
||||
}
|
||||
// Language and Languages types are imported at the top from languages-server
|
||||
export type { Language, Languages }
|
||||
|
||||
export type Permalink = {
|
||||
languageCode: string
|
||||
|
||||
Reference in New Issue
Block a user