1
0
mirror of synced 2025-12-19 18:10:59 -05:00

don't get available languages from session (#29715)

* don't get available languages from session

* update useSession

* one more fix
This commit is contained in:
Peter Bengtsson
2022-08-08 17:13:27 +02:00
committed by GitHub
parent f73fb93f51
commit a1e3866fa5
14 changed files with 67 additions and 93 deletions

View File

@@ -6,13 +6,13 @@ import { Flash, Label, ActionList, ActionMenu } from '@primer/react'
import { ItemInput } from '@primer/react/lib/deprecated/ActionList/List'
import { InfoIcon } from '@primer/octicons-react'
import { useLanguages } from 'components/context/LanguagesContext'
import { useTranslation } from 'components/hooks/useTranslation'
import { sendEvent, EventType } from 'components/lib/events'
import { useMainContext } from './context/MainContext'
import { DEFAULT_VERSION, useVersion } from 'components/hooks/useVersion'
import { useQuery } from 'components/hooks/useQuery'
import { Link } from 'components/Link'
import { useSession } from 'components/hooks/useSession'
import styles from './Search.module.scss'
@@ -56,8 +56,7 @@ export function Search({
const inputRef = useRef<HTMLInputElement>(null)
const { t } = useTranslation('search')
const { currentVersion } = useVersion()
const { session } = useSession()
const languages = session?.languages
const { languages } = useLanguages()
// Figure out language and version for index
const { searchVersions, nonEnterpriseDefaultVersion } = useMainContext()

View File

@@ -0,0 +1,24 @@
import { createContext, useContext } from 'react'
type LanguageItem = {
name: string
nativeName?: string
code: string
hreflang: string
}
export type LanguagesContextT = {
languages: Record<string, LanguageItem>
}
export const LanguagesContext = createContext<LanguagesContextT | null>(null)
export const useLanguages = (): LanguagesContextT => {
const context = useContext(LanguagesContext)
if (!context) {
throw new Error('"useLanguagesContext" may only be used inside "LanguagesContext.Provider"')
}
return context
}

View File

@@ -9,19 +9,10 @@ export default async function fetcher<JSON = any>(
return res.json()
}
type LanguageItem = {
name: string
nativeName?: string
code: string
hreflang: string
wip?: boolean
}
export type Session = {
isSignedIn: boolean
csrfToken: string
userLanguage: string // en, es, ja, cn
languages: Record<string, LanguageItem>
theme: {
colorMode: Pick<ThemeProviderProps, 'colorMode'>
nightTheme: string

View File

@@ -1,6 +1,7 @@
import { useRouter } from 'next/router'
import cx from 'classnames'
import { useLanguages } from 'components/context/LanguagesContext'
import { useMainContext } from 'components/context/MainContext'
import { useTranslation } from 'components/hooks/useTranslation'
import { ExcludesNull } from 'components/lib/ExcludesNull'
@@ -24,13 +25,13 @@ export const HeaderNotifications = () => {
const { relativePath, allVersions, data, currentPathWithoutLanguage, page } = useMainContext()
const { session } = useSession()
const userLanguage = session?.userLanguage
const languages = session?.languages || {}
const { languages } = useLanguages()
const { t } = useTranslation('header')
const translationNotices: Array<Notif> = []
if (router.locale === 'en') {
if (userLanguage && userLanguage !== 'en' && languages[userLanguage]?.wip === false) {
if (userLanguage && userLanguage !== 'en') {
translationNotices.push({
type: NotificationType.TRANSLATION,
content: `This article is also available in <a href="/${userLanguage}${currentPathWithoutLanguage}">${languages[userLanguage]?.name}</a>.`,
@@ -42,16 +43,11 @@ export const HeaderNotifications = () => {
type: NotificationType.TRANSLATION,
content: data.reusables.policies.translation,
})
} else if (router.locale && languages[router.locale]?.wip !== true) {
} else if (router.locale) {
translationNotices.push({
type: NotificationType.TRANSLATION,
content: t('notices.localization_complete'),
})
} else if (router.locale && languages[router.locale]?.wip) {
translationNotices.push({
type: NotificationType.TRANSLATION,
content: t('notices.localization_in_progress'),
})
}
}
const releaseNotices: Array<Notif> = []

View File

@@ -1,7 +1,7 @@
import { useRouter } from 'next/router'
import Cookies from 'js-cookie'
import { useSession } from 'components/hooks/useSession'
import { useLanguages } from 'components/context/LanguagesContext'
import { Picker } from 'components/ui/Picker'
import { useTranslation } from 'components/hooks/useTranslation'
@@ -14,14 +14,12 @@ type Props = {
export const LanguagePicker = ({ variant }: Props) => {
const router = useRouter()
const { session } = useSession()
const languages = session?.languages
const { languages } = useLanguages()
const locale = router.locale || 'en'
const { t } = useTranslation('picker')
if (!languages) return null
const langs = Object.values(languages)
const selectedLang = languages[locale]
@@ -52,15 +50,13 @@ export const LanguagePicker = ({ variant }: Props) => {
<Picker
variant={variant}
defaultText={t('language_picker_default_text')}
options={langs
.filter((lang) => !lang.wip)
.map((lang) => ({
text: lang.nativeName || lang.name,
selected: lang === selectedLang,
locale: lang.code,
href: `${routerPath}`,
onselect: rememberPreferredLanguage,
}))}
options={langs.map((lang) => ({
text: lang.nativeName || lang.name,
selected: lang === selectedLang,
locale: lang.code,
href: `${routerPath}`,
onselect: rememberPreferredLanguage,
}))}
/>
</div>
)

View File

@@ -6,7 +6,6 @@ const languages = {
code: 'en',
hreflang: 'en',
dir: '',
wip: false,
},
cn: {
name: 'Simplified Chinese',
@@ -15,7 +14,6 @@ const languages = {
hreflang: 'zh-Hans',
redirectPatterns: [/^\/zh-\w{2}/, /^\/zh/],
dir: 'translations/zh-CN',
wip: false,
},
ja: {
name: 'Japanese',
@@ -24,7 +22,6 @@ const languages = {
hreflang: 'ja',
redirectPatterns: [/^\/jp/],
dir: 'translations/ja-JP',
wip: false,
},
es: {
name: 'Spanish',
@@ -32,7 +29,6 @@ const languages = {
code: 'es',
hreflang: 'es',
dir: 'translations/es-ES',
wip: false,
},
pt: {
name: 'Portuguese',
@@ -40,7 +36,6 @@ const languages = {
code: 'pt',
hreflang: 'pt',
dir: 'translations/pt-BR',
wip: false,
},
}

View File

@@ -11,7 +11,6 @@ router.get('/', (req, res) => {
isSignedIn: Boolean(req.cookies?.dotcom_user),
csrfToken: req.csrfToken?.() || '',
userLanguage: req.userLanguage,
languages: req.context.languages,
theme: getTheme(req),
themeCss: getTheme(req, true),
})

View File

@@ -1,13 +1,7 @@
import languages from '../lib/languages.js'
import { productMap } from '../lib/all-products.js'
import { deprecated } from '../lib/enterprise-server-releases.js'
const pathRegExps = [
// Disallow indexing of WIP localized content
...Object.values(languages)
.filter((language) => language.wip)
.map((language) => new RegExp(`^/${language.code}(/.*)?$`, 'i')),
// Disallow indexing of WIP products
...Object.values(productMap)
.filter((product) => product.wip || product.hidden)

View File

@@ -36,8 +36,7 @@ function getUserLanguage(browserLanguages) {
function getUserLanguageFromCookie(req) {
const value = req.cookies[PREFERRED_LOCALE_COOKIE_NAME]
// But if it's a WIP language, reject it.
if (value && languages[value] && !languages[value].wip) {
if (value && languages[value]) {
return value
}
}

View File

@@ -8,15 +8,17 @@ import '../stylesheets/index.scss'
import events from 'components/lib/events'
import experiment from 'components/lib/experiment'
import { LanguagesContext, LanguagesContextT } from 'components/context/LanguagesContext'
import { useSession } from 'components/hooks/useSession'
type MyAppProps = AppProps & {
isDotComAuthenticated: boolean
languagesContext: LanguagesContextT
}
type colorModeAuto = Pick<ThemeProviderProps, 'colorMode'>
const MyApp = ({ Component, pageProps }: MyAppProps) => {
const MyApp = ({ Component, pageProps, languagesContext }: MyAppProps) => {
const { session, isLoadingSession } = useSession()
useEffect(() => {
events(session?.csrfToken)
@@ -67,7 +69,9 @@ const MyApp = ({ Component, pageProps }: MyAppProps) => {
{ opacity: isLoadingSession ? 0.1 : 1 }
}
>
<Component {...pageProps} />
<LanguagesContext.Provider value={languagesContext}>
<Component {...pageProps} />
</LanguagesContext.Provider>
</div>
</ThemeProvider>
</SSRProvider>
@@ -80,11 +84,18 @@ const MyApp = ({ Component, pageProps }: MyAppProps) => {
// executed every time **in the client** if it was the first time
// ever (since restart) or from a cached HTML.
MyApp.getInitialProps = async (appContext: AppContext) => {
const { ctx } = appContext
// calls page's `getInitialProps` and fills `appProps.pageProps`
const appProps = await App.getInitialProps(appContext)
const req: any = ctx.req
// Have to define the type manually here because `req.context.languages`
// comes from Node JS and is not type-aware.
const languages: LanguagesContextT = req.context.languages
return {
...appProps,
languagesContext: { languages },
}
}

View File

@@ -40,7 +40,7 @@ async function main() {
const languageCodes =
[languageCode] ||
Object.keys(languages)
.filter((language) => !language.wip && language !== 'en')
.filter((language) => language !== 'en')
.map((language) => languages[language].code)
const versions = singleVersion ? [singleVersion] : Object.keys(allVersions)

View File

@@ -1,6 +1,5 @@
import { jest } from '@jest/globals'
import { latest, oldestSupported } from '../../lib/enterprise-server-releases.js'
import languages from '../../lib/languages.js'
jest.useFakeTimers({ legacyFakeTimers: true })
@@ -421,22 +420,6 @@ describe('filter cards', () => {
})
})
describe('language banner', () => {
it('directs user to the English version of the article', async () => {
const wipLanguageKey = Object.keys(languages).find((key) => languages[key].wip)
// This kinda sucks, but if we don't have a WIP language, we currently can't
// run a reliable test. But hey, on the bright side, if we don't have a WIP
// language then this code will never run anyway!
if (wipLanguageKey) {
const res = await page.goto(`http://localhost:4000/${wipLanguageKey}/actions`)
expect(res.ok()).toBe(true)
const href = await page.$eval('a#to-english-doc', (el) => el.href)
expect(href.endsWith('/en/actions')).toBe(true)
}
})
})
// Skipping because next/links are disabled by default for now
// Docs Engineering issue: 962
describe.skip('next/link client-side navigation', () => {

View File

@@ -15,21 +15,10 @@ describe('block robots', () => {
})
it('allows crawling of generally available localized content', async () => {
Object.values(languages)
.filter((language) => !language.wip)
.forEach((language) => {
expect(allowIndex(`/${language.code}`)).toBe(true)
expect(allowIndex(`/${language.code}/articles/verifying-your-email-address`)).toBe(true)
})
})
it('disallows crawling of WIP localized content', async () => {
Object.values(languages)
.filter((language) => language.wip)
.forEach((language) => {
expect(allowIndex(`/${language.code}`)).toBe(false)
expect(allowIndex(`/${language.code}/articles/verifying-your-email-address`)).toBe(false)
})
Object.values(languages).forEach((language) => {
expect(allowIndex(`/${language.code}`)).toBe(true)
expect(allowIndex(`/${language.code}/articles/verifying-your-email-address`)).toBe(true)
})
})
it('disallows crawling of WIP products', async () => {

View File

@@ -25,16 +25,14 @@ describe('robots.txt', () => {
})
it('allows indexing of generally available localized content', async () => {
Object.values(languages)
.filter((language) => !language.wip)
.forEach((language) => {
expect(robots.isAllowed(`https://docs.github.com/${language.code}`)).toBe(true)
expect(
robots.isAllowed(
`https://docs.github.com/${language.code}/articles/verifying-your-email-address`
)
).toBe(true)
})
Object.values(languages).forEach((language) => {
expect(robots.isAllowed(`https://docs.github.com/${language.code}`)).toBe(true)
expect(
robots.isAllowed(
`https://docs.github.com/${language.code}/articles/verifying-your-email-address`
)
).toBe(true)
})
})
it('disallows indexing of azurecontainer.io domains', async () => {