Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React i18next #8866

Merged
merged 65 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
1798fe5
Revert "Merge pull request #8786 from ethereum/revert-i18n-pr"
pettinarip Dec 10, 2022
5c330b8
update queries to fetch the corresponding namespaces
pettinarip Dec 6, 2022
3c1a6cc
remove dynamic translation keys
pettinarip Dec 8, 2022
8f4b43e
update queries to fetch the corresponding namespaces
pettinarip Dec 8, 2022
8a038cc
add i18n scanner
pettinarip Dec 8, 2022
e150efd
create ts script to scan & extract translation strings
pettinarip Dec 9, 2022
5b5c9ca
update translation queries for the templates
pettinarip Dec 9, 2022
d411fce
simplify namespace generation function
pettinarip Dec 10, 2022
078c967
fix replaceAll function
pettinarip Dec 10, 2022
32ae184
remove log
pettinarip Dec 10, 2022
b6d19df
fix types
pettinarip Dec 12, 2022
b202358
add documentation on createLocales script
pettinarip Dec 19, 2022
6f6f62d
Merge branch 'dev' into i18n-extract-strings
pettinarip Dec 19, 2022
eda0cff
docs: explain locales generation process
pettinarip Dec 19, 2022
f724fd8
Merge branch 'dev' into i18n-extract-strings
pettinarip Jan 3, 2023
e752dff
adapt Trilemma to use new intl lib
pettinarip Jan 3, 2023
04550c1
Merge branch 'dev' into i18n-extract-strings
pettinarip Jan 3, 2023
d259ecd
fix hydration issue using new intl lib
pettinarip Jan 4, 2023
ae5d9fb
clean locales folder before creating the new locales again
pettinarip Jan 4, 2023
ca4c74b
preserve the defaultLang values when merging the intl json files
pettinarip Jan 4, 2023
cfade8c
Apply suggestions from code review
pettinarip Jan 5, 2023
d2931e8
fix issues from pr review
pettinarip Jan 5, 2023
472174d
update page queries
pettinarip Jan 15, 2023
1121f54
create locales
pettinarip Jan 15, 2023
8dc9886
generate locales only for supported languages
pettinarip Jan 19, 2023
789376b
delete mergeTranslations script
pettinarip Jan 19, 2023
e3c74c2
bump i18n deps
pettinarip Jan 20, 2023
6cc04d0
reorder translations
pettinarip Jan 21, 2023
43cab21
add script to detect unused translation keys
pettinarip Jan 23, 2023
03d7f9e
remove unused translations
pettinarip Jan 23, 2023
2c5ad4f
cleanup common namespace
pettinarip Jan 24, 2023
78f9e15
add docs
pettinarip Jan 24, 2023
9b9e5c6
turn on lowerCaseLng flag to be able to use zh-TW and pt-BR
pettinarip Jan 25, 2023
de72e68
fix tutorials links
pettinarip Jan 25, 2023
6447f1b
update translation
pettinarip Jan 25, 2023
966f4b0
Merge branch 'dev' into i18n-extract-strings
pettinarip Jan 27, 2023
886fb46
fixes after merging
pettinarip Jan 27, 2023
3746e62
Merge branch 'i18n-extract-strings' into i18n-rework
pettinarip Jan 27, 2023
9789abf
update yarn.lock
pettinarip Jan 27, 2023
f174d3a
update languages.json translations
pettinarip Jan 27, 2023
e3aab9d
regenerate yarn.lock
pettinarip Jan 28, 2023
76f1e98
fix Breadcrumbs
pettinarip Jan 28, 2023
38e2f37
change translation key for learn hub title
pettinarip Jan 30, 2023
d0a9fdf
update docs
pettinarip Jan 30, 2023
d0cf89f
remove deps
pettinarip Jan 30, 2023
1f715d4
reorder translations
pettinarip Jan 30, 2023
ec415b5
add translations for learning quizzes
pettinarip Feb 1, 2023
344fa22
reorg translations
pettinarip Feb 2, 2023
71f234d
add script to reorg intl translations
pettinarip Feb 4, 2023
8385f4b
add missing translations
pettinarip Mar 2, 2023
a9ed184
Merge branch 'dev' into i18n-extract-strings
pettinarip Mar 3, 2023
b9195e2
install new deps
pettinarip Mar 3, 2023
dd3f0ae
Merge branch 'dev' into i18n-extract-strings
pettinarip Mar 3, 2023
1978a39
Merge branch 'i18n-extract-strings' into i18n-rework
pettinarip Mar 3, 2023
b07066e
regenerate yarn.lock
pettinarip Mar 6, 2023
c0db325
add locales query on new templates
pettinarip Mar 6, 2023
30efac1
run reorg-intl
pettinarip Mar 6, 2023
69a045d
Merge pull request #9261 from ethereum/i18n-rework
pettinarip Mar 6, 2023
f51ca6b
Merge branch 'dev' into i18n-extract-strings
pettinarip Mar 6, 2023
8918fdc
Merge branch 'dev' into i18n-extract-strings
pettinarip Mar 7, 2023
a595c0c
Merge branch 'dev' into i18n-extract-strings
pettinarip Mar 8, 2023
027ecef
fixes
pettinarip Mar 8, 2023
307c758
Merge branch 'dev' into i18n-extract-strings
pettinarip Mar 8, 2023
a1259ba
Merge branch 'dev' into i18n-extract-strings
pettinarip Mar 9, 2023
d9342b0
remove unused gatsby-ssr file
pettinarip Mar 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ yarn-error.log
src/data/contributors.json
# These files are generated by `yarn merge-translations` command
src/intl/*.json
i18n/locales
i18n/merged
# Auto generated code when gatsby build the site
src/gatsby-types.d.ts

Expand Down
9 changes: 9 additions & 0 deletions docs/locales-process.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Locales generation process

Every time `yarn build` or `yarn start` is executed, the following process is
going to be triggered as well:

<img src="./locales.png">

With this process, we reduce the amount of text we bundle on each page since we
are querying only the necessary translations that each page needs.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit of context on how the whole process works. Would appreciate any feedback on this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also a recommended thing to read first that will help you understand and review the PR.

Binary file added docs/locales.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 0 additions & 51 deletions gatsby-browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
* See: https://www.gatsbyjs.org/docs/browser-apis/
*/

import React from "react"
import browserLang from "browser-lang"
import { withPrefix, GatsbyBrowser } from "gatsby"

import Prism from "prism-react-renderer/prism"
;(typeof global !== "undefined" ? global : window).Prism = Prism

Expand All @@ -16,53 +12,6 @@ import "@formatjs/intl-locale/polyfill"
import "@formatjs/intl-numberformat/polyfill"
import "@formatjs/intl-numberformat/locale-data/en"

import Layout from "./src/components/Layout"
import {
supportedLanguages,
defaultLanguage,
isLang,
} from "./src/utils/languages"
import { IS_DEV } from "./src/utils/env"
import { Context } from "./src/types"

// Default languages included:
// https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/vendor/prism/includeLangs.js
require("prismjs/components/prism-solidity")

// Prevents <Layout/> from unmounting on page transitions
// https://www.gatsbyjs.com/docs/layout-components/#how-to-prevent-layout-components-from-unmounting
// @ts-ignore: returning `null` is not accepted by the `GatsbyBrowser` type def.
export const wrapPageElement: GatsbyBrowser<
any,
Context
>["wrapPageElement"] = ({ element, props }) => {
const { location, pageContext } = props
const { pathname, search } = location
const { originalPath } = pageContext

const [, pathLocale] = pathname.split("/")

// client side redirect on paths that don't have a locale in them. Most useful
// on dev env where we don't have server redirects
if (IS_DEV && !isLang(pathLocale)) {
let detected =
window.localStorage.getItem("eth-org-language") ||
browserLang({
languages: supportedLanguages,
fallback: defaultLanguage,
})

if (!isLang(detected)) {
detected = defaultLanguage
}

const queryParams = search || ""
const newUrl = withPrefix(`/${detected}${originalPath}${queryParams}`)
window.localStorage.setItem("eth-org-language", detected)
window.location.replace(newUrl)

return null
}

return <Layout {...props}>{element}</Layout>
}
71 changes: 53 additions & 18 deletions gatsby-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,6 @@ const config: GatsbyConfig = {
editContentUrl: `https://github.com/ethereum/ethereum-org-website/tree/dev/`,
},
plugins: [
// i18n support
{
resolve: `gatsby-theme-i18n`,
options: {
defaultLang: defaultLanguage,
prefixDefault: true,
locales: supportedLanguages.length
? supportedLanguages.join(" ")
: null,
configPath: path.resolve(`./i18n/config.json`),
},
},
{
resolve: `gatsby-theme-i18n-react-intl`,
options: {
defaultLocale: `./src/intl/en.json`,
},
},
// Web app manifest
{
resolve: `gatsby-plugin-manifest`,
Expand Down Expand Up @@ -266,6 +248,59 @@ const config: GatsbyConfig = {
generateMatchPathRewrites: false,
},
},
// i18n support
{
resolve: `gatsby-source-filesystem`,
options: {
path: path.resolve(`./i18n/locales`),
name: `locale`,
},
},
// Wraps the entire page with a custom layout component
// Note: keep this before the i18n plugin declaration in order to have the
// i18n provider wrapping the layout component
{
resolve: `gatsby-plugin-layout`,
options: {
component: path.resolve(`./src/components/Layout`),
},
},
{
resolve: `gatsby-plugin-react-i18next`,
options: {
localeJsonSourceName: `locale`, // name given to `gatsby-source-filesystem` plugin.
languages: supportedLanguages,
defaultLanguage,
generateDefaultLanguagePage: true,
redirect: false,
siteUrl,
trailingSlash: "always",
// i18next options
i18nextOptions: {
fallbackLng: defaultLanguage,
interpolation: {
escapeValue: false,
},
load: "currentOnly",
lowerCaseLng: true,
cleanCode: true,
react: {
transSupportBasicHtmlNodes: true,
transKeepBasicHtmlNodesFor: [
"br",
"strong",
"i",
"bold",
"b",
"em",
"sup",
],
},
keySeparator: false,
nsSeparator: false,
},
},
},
],
// https://www.gatsbyjs.com/docs/reference/release-notes/v2.28/#feature-flags-in-gatsby-configjs
flags: {
Expand Down
139 changes: 87 additions & 52 deletions gatsby-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { Context } from "./src/types"

import * as Schema from "./src/schema"

import mergeTranslations from "./src/scripts/mergeTranslations"
import createLocales from "./src/scripts/createLocales"
import copyContributors from "./src/scripts/copyContributors"

import {
Expand Down Expand Up @@ -284,17 +284,23 @@ export const createPages: GatsbyNode<any, Context>["createPages"] = async ({
component: path.resolve(`src/templates/${template}.tsx`),
context: {
language: lang,
languagesToFetch: [lang],
slug: langSlug,
ignoreTranslationBanner: isLegal,
isLegal: isLegal,
isOutdated: false,
isContentEnglish: true,
relativePath, // Use English path for template MDX query
// gatsby i18n theme context
locale: lang,
hrefLang: lang,
originalPath: langSlug.slice(3),
dateFormat: "MM/DD/YYYY",
// gatsby i18n plugin
i18n: {
language: lang,
languages: supportedLanguages,
defaultLanguage: defaultLanguage,
generateDefaultLanguagePage: false,
routed: true,
originalPath: langSlug.slice(3),
path: langSlug,
},
},
})
}
Expand All @@ -306,15 +312,21 @@ export const createPages: GatsbyNode<any, Context>["createPages"] = async ({
component: path.resolve(`src/templates/${template}.tsx`),
context: {
language,
languagesToFetch: [language],
slug,
isOutdated: !!node.fields.isOutdated,
isDefaultLang: language === defaultLanguage,
relativePath,
// gatsby i18n theme context
locale: language,
hrefLang: language,
originalPath: slug.slice(3),
dateFormat: "MM/DD/YYYY",
// gatsby i18n plugin
i18n: {
language,
languages: supportedLanguages,
defaultLanguage,
generateDefaultLanguagePage: false,
routed: true,
originalPath: slug.slice(3),
path: slug,
},
},
})
})
Expand Down Expand Up @@ -344,22 +356,26 @@ export const createPages: GatsbyNode<any, Context>["createPages"] = async ({
page,
lang
)

const slug = `/${lang}${originalPath}`

createPage<Context>({
path: slug,
component: path.resolve(`src/pages-conditional/${page}.tsx`),
context: {
language: lang,
languagesToFetch: [lang],
slug,
isContentEnglish,
isOutdated,
// gatsby i18n theme context
locale: lang,
hrefLang: lang,
originalPath,
dateFormat: "MM/DD/YYYY",
// gatsby i18n plugin
i18n: {
language: lang,
languages: supportedLanguages,
defaultLanguage,
generateDefaultLanguagePage: false,
routed: true,
originalPath,
path: slug,
},
},
})
}
Expand All @@ -376,51 +392,68 @@ export const onCreatePage: GatsbyNode<any, Context>["onCreatePage"] = async ({
}) => {
const { createPage, deletePage, createRedirect } = actions

const isDefaultLang = page.path.startsWith(`/${defaultLanguage}`)

if (isDefaultLang) {
const path = page.path.slice(3)

if (IS_DEV) {
// create routes without the lang prefix e.g. `/{path}` as our i18n plugin
// only creates `/{lang}/{path}` routes. This is useful on dev env to avoid
// getting a 404 since we don't have server side redirects
createPage({ ...page, path })
}

if (!IS_DEV && !path.match(/^\/404(\/|.html)$/)) {
// on prod, indicate our servers to redirect the root paths to the
// `/{defaultLang}/{path}`
createRedirect({
...commonRedirectProps,
fromPath: path,
toPath: page.path,
})
}
}

if (!page.context) {
return
}

const isTranslated = page.context.locale !== defaultLanguage
const hasNoContext = page.context.isOutdated === undefined
// these are the native Gatsby pages (those living under `/pages`)
// which do not pass through the `createPages` hook thus they don't have our
// custom context in them
const isPageWithoutCustomContext = page.context.isOutdated === undefined

if (isTranslated && hasNoContext) {
if (isPageWithoutCustomContext) {
const { language, i18n } = page.context
const isDefaultLang = language === defaultLanguage

// as we don't have our custom context for this page, we calculate & add it
// later to them
const { isOutdated, isContentEnglish } = await checkIsPageOutdated(
page.context.originalPath,
page.context.locale
i18n.originalPath,
language
)
deletePage(page)
createPage<Context>({

let newPage = {
...page,
context: {
...page.context,
languagesToFetch: [language],
isOutdated,
//display TranslationBanner for translation-component pages that are still in English
isContentEnglish,
},
})
}

// there seems to be a bug in the i18n plugin where 404 pages get a
// duplicated `/lang` in their `matchPath`s
if (newPage.matchPath?.includes(`/${language}/${language}/*`)) {
newPage = { ...newPage, matchPath: `/${language}/*` }
}

// on dev, we will have 2 pages for the default lang
// - 1 for the ones with the prefix `/{defaultLang}/learn/`
// - 1 for the ones without the prefix `/learn/`
// we do this to avoid having a 404 on those without the prefix since in
// dev we don't have the redirects from the server
deletePage(page)

if (IS_DEV) {
createPage<Context>(newPage)
}

// `routed` means that the page have the lang prefix on the url
// e.g. `/en/learn` or `/en`
if (!IS_DEV && i18n.routed) {
createPage<Context>(newPage)

const rootPath = page.path.slice(3)
if (isDefaultLang && !rootPath.match(/^\/404(\/|.html)$/)) {
createRedirect({
...commonRedirectProps,
fromPath: rootPath,
toPath: page.path,
})
}
}
}
}

Expand All @@ -446,9 +479,11 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"]
createTypes([...Object.keys(sdls).map((sdlKey) => sdls[sdlKey])])
}

export const onPreBootstrap: GatsbyNode["onPreBootstrap"] = ({ reporter }) => {
mergeTranslations()
reporter.info(`Merged translations saved`)
export const onPreBootstrap: GatsbyNode["onPreBootstrap"] = async ({
reporter,
}) => {
await createLocales()
reporter.info(`Created locales`)
copyContributors()
reporter.info(`Contributors copied`)
}
Expand Down
Loading