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

Set up i18n package #6991

Merged
merged 16 commits into from
Sep 13, 2024
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/translations-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ on:
- 'apps/site/pages/**/*.mdx'
- '!apps/site/pages/en/**/*.md'
- '!apps/site/pages/en/**/*.mdx'
- 'apps/site/i18n/locales/*.json'
- '!apps/site/i18n/locales/en.json'
- 'packages/i18n/locales/*.json'
- '!packages/i18n/locales/en.json'

permissions:
actions: read
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ tsconfig.tsbuildinfo

# Sentry Config File
.sentryclirc

dist/
3 changes: 0 additions & 3 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# lint and format staged files
npx lint-staged

Expand Down
2 changes: 1 addition & 1 deletion apps/site/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import englishLocale from '@node-core/website-i18n/locales/en.json';
import { withThemeByDataAttribute } from '@storybook/addon-themes';
import type { Preview, ReactRenderer } from '@storybook/react';
import { NextIntlClientProvider } from 'next-intl';

import { STORYBOOK_MODES, STORYBOOK_SIZES } from '@/.storybook/constants';
import englishLocale from '@/i18n/locales/en.json';
import { NotificationProvider } from '@/providers/notificationProvider';

import '../next.fonts';
Expand Down
3 changes: 1 addition & 2 deletions apps/site/components/Common/LanguageDropDown/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { LanguageIcon } from '@heroicons/react/24/outline';
import type { LocaleConfig } from '@node-core/website-i18n/types';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import classNames from 'classnames';
import { useTranslations } from 'next-intl';
import type { FC } from 'react';

import type { LocaleConfig } from '@/types';

import styles from './index.module.css';

type SimpleLocaleConfig = Pick<LocaleConfig, 'name' | 'code'>;
Expand Down
10 changes: 3 additions & 7 deletions apps/site/components/Downloads/Release/ReleaseCodeBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ import type { FC } from 'react';

import CodeBox from '@/components/Common/CodeBox';
import { ReleaseContext } from '@/providers/releaseProvider';
import { getShiki, highlightToHtml } from '@/util/getHighlighter';
import { shikiPromise, highlightToHtml } from '@/util/getHighlighter';
import { getNodeDownloadSnippet } from '@/util/getNodeDownloadSnippet';

// We cannot do top-level awaits on utilities or code that is imported by client-only components
// hence we only declare a Promise and let it be fulfilled by the first call to the function
const memoizedShiki = getShiki();
const memoizedShiki = shikiPromise.then(highlightToHtml);

const ReleaseCodeBox: FC = () => {
const { platform, os, release } = useContext(ReleaseContext);
Expand All @@ -25,9 +23,7 @@ const ReleaseCodeBox: FC = () => {
// but usually we should recommend users to download "major" versions
// since our Download Buttons get the latest minor of a major, it does make sense
// to request installation of a major via a package manager
memoizedShiki
.then(shiki => highlightToHtml(shiki)(updatedCode, 'bash'))
.then(setCode);
memoizedShiki.then(shiki => shiki(updatedCode, 'bash')).then(setCode);
// Only react when the specific release number changed
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [release.versionWithPrefix, os, platform]);
Expand Down
29 changes: 9 additions & 20 deletions apps/site/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { fixupPluginRules } from '@eslint/compat';
import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
import importX from 'eslint-plugin-import-x';
Expand All @@ -9,27 +8,16 @@ import storybook from 'eslint-plugin-storybook';
import tseslint from 'typescript-eslint';

const compat = new FlatCompat();
const pluginToPatch = '@next/next';

const compatConfig = compat
.config({
extends: [
// https://github.com/vercel/next.js/discussions/49337
'plugin:@next/eslint-plugin-next/core-web-vitals',

// https://github.com/facebook/react/issues/28313
'plugin:react-hooks/recommended',
],
})
.map(entry => {
if (Object.hasOwn(entry.plugins, pluginToPatch)) {
entry.plugins[pluginToPatch] = fixupPluginRules(
entry.plugins[pluginToPatch]
);
}
const compatConfig = compat.config({
extends: [
// https://github.com/vercel/next.js/discussions/49337
'plugin:@next/eslint-plugin-next/core-web-vitals',

return entry;
});
// https://github.com/facebook/react/issues/28313
'plugin:react-hooks/recommended',
],
});

export default tseslint.config(
{
Expand Down Expand Up @@ -58,6 +46,7 @@ export default tseslint.config(
'no-relative-import-paths': noRelativeImportPaths,
},
rules: {
'@next/next/no-duplicate-head': 'off',
'@typescript-eslint/array-type': ['error', { default: 'generic' }],
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/no-require-imports': 'off',
Expand Down
7 changes: 5 additions & 2 deletions apps/site/i18n.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { importLocale } from '@node-core/website-i18n';
ovflowd marked this conversation as resolved.
Show resolved Hide resolved
import { getRequestConfig } from 'next-intl/server';

import { availableLocaleCodes } from '@/next.locales.mjs';
Expand All @@ -7,13 +8,15 @@ const loadLocaleDictionary = async (locale: string) => {
if (locale === 'en') {
// This enables HMR on the English Locale, so that instant refresh
// happens while we add/change texts on the source locale
return import('./i18n/locales/en.json').then(f => f.default);
return import('@node-core/website-i18n/locales/en.json').then(
f => f.default
);
}

if (availableLocaleCodes.includes(locale)) {
// Other languages don't really require HMR as they will never be development languages
// so we can load them dynamically
return import(`./i18n/locales/${locale}.json`).then(f => f.default);
return importLocale(locale);
}

throw new Error(`Unsupported locale: ${locale}`);
Expand Down
2 changes: 1 addition & 1 deletion apps/site/next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
/// <reference types="next/navigation-types/compat/navigation" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
22 changes: 13 additions & 9 deletions apps/site/next.locales.mjs
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
'use strict';
ovflowd marked this conversation as resolved.
Show resolved Hide resolved

import localeConfig from './i18n/config.json' assert { type: 'json' };
import {
getAvailableLocales,
getAvailableLocaleCodes,
getDefaultLocale,
getAvailableLocalesMap,
getAllLocaleCodes,
} from '@node-core/website-i18n';

// As set of available and enabled locales for the website
// This is used for allowing us to redirect the user to any
// of the available locales that we have enabled on the website
const availableLocales = localeConfig.filter(locale => locale.enabled);
const availableLocales = getAvailableLocales();

// This gives an easy way of accessing all available locale codes
const availableLocaleCodes = availableLocales.map(locale => locale.code);
const availableLocaleCodes = getAvailableLocaleCodes();

// This provides the default locale information for the Next.js Application
// This is marked by the unique `locale.default` property on the `en` locale
/** @type {import('./types').LocaleConfig} */
const defaultLocale = availableLocales.find(locale => locale.default);
/** @type {import('@node-core/website-i18n/types').LocaleConfig} */
const defaultLocale = getDefaultLocale();

// Creates a Map of available locales for easy access
const availableLocalesMap = Object.fromEntries(
localeConfig.map(locale => [locale.code, locale])
);
const availableLocalesMap = getAvailableLocalesMap();

// Creates all supported locales
const allLocaleCodes = localeConfig.map(locale => locale.code);
const allLocaleCodes = getAllLocaleCodes();

export {
allLocaleCodes,
Expand Down
9 changes: 3 additions & 6 deletions apps/site/next.mdx.shiki.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import classNames from 'classnames';
import { toString } from 'hast-util-to-string';
import { SKIP, visit } from 'unist-util-visit';

import { getShiki, highlightToHast } from './util/getHighlighter';
import { shikiPromise, highlightToHast } from './util/getHighlighter';

// This is what Remark will use as prefix within a <pre> className
// to attribute the current language of the <pre> element
Expand Down Expand Up @@ -58,7 +58,7 @@ export default function rehypeShikiji() {
// We do a top-level await, since the Unist-tree visitor
// is synchronous, and it makes more sense to do a top-level
// await, rather than an await inside the visitor function
const memoizedShiki = await getShiki();
const memoizedShiki = highlightToHast(await shikiPromise);

visit(tree, 'element', (_, index, parent) => {
const languages = [];
Expand Down Expand Up @@ -174,10 +174,7 @@ export default function rehypeShikiji() {
const languageId = codeLanguage.slice(languagePrefix.length);

// Parses the <pre> contents and returns a HAST tree with the highlighted code
const { children } = highlightToHast(memoizedShiki)(
preElementContents,
languageId
);
const { children } = memoizedShiki(preElementContents, languageId);

// Adds the original language back to the <pre> element
children[0].properties.class = classNames(
Expand Down
97 changes: 47 additions & 50 deletions apps/site/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"type": "module",
"private": true,
"name": "@nodejs/website",
"name": "@node-core/website",
"description": "Nodejs.org Website",
"homepage": "https://nodejs.org",
"repository": {
Expand Down Expand Up @@ -38,96 +38,93 @@
"dependencies": {
"@heroicons/react": "~2.1.5",
"@mdx-js/mdx": "^3.0.1",
"@node-core/website-i18n": "*",
"@nodevu/core": "~0.1.0",
"@orama/highlight": "^0.1.6",
"@oramacloud/client": "^1.3.2",
"@radix-ui/react-accessible-icon": "^1.0.3",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@oramacloud/client": "^1.3.15",
"@radix-ui/react-accessible-icon": "^1.1.0",
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-toast": "^1.2.1",
"@savvywombat/tailwindcss-grid-areas": "~4.0.0",
"@sentry/nextjs": "~8.14.0",
"@sentry/nextjs": "~8.30.0",
"@tailwindcss/container-queries": "~0.1.1",
"@types/node": "20.16.3",
"@types/node": "20.16.5",
"@vcarl/remark-headings": "~0.1.0",
"@vercel/analytics": "~1.3.1",
"@vercel/speed-insights": "~1.0.10",
"autoprefixer": "~10.4.18",
"@vercel/speed-insights": "~1.0.12",
"autoprefixer": "~10.4.20",
"classnames": "~2.5.1",
"cross-env": "7.0.3",
"dedent": "1.5.3",
"feed": "~4.2.2",
"github-slugger": "~2.0.0",
"glob": "~10.4.1",
"glob": "~11.0.0",
"gray-matter": "~4.0.3",
"next": "~14.2.7",
"next-intl": "~3.19.0",
"next": "~14.2.11",
"next-intl": "~3.19.1",
"next-themes": "~0.3.0",
"postcss": "~8.4.40",
"postcss-calc": "~10.0.0",
"postcss": "~8.4.45",
"postcss-calc": "~10.0.2",
"postcss-import": "~16.1.0",
"postcss-mixins": "~10.0.1",
"postcss-mixins": "~11.0.1",
"postcss-simple-vars": "~7.0.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"rehype-autolink-headings": "~7.1.0",
"rehype-slug": "~6.0.0",
"remark-gfm": "~4.0.0",
"remark-reading-time": "~2.0.1",
"semver": "~7.6.0",
"shiki": "~1.15.2",
"tailwindcss": "^3.4.7",
"typescript": "~5.5.3",
"semver": "~7.6.3",
"shiki": "~1.17.5",
"tailwindcss": "^3.4.11",
"unist-util-visit": "~5.0.0",
"vfile": "~6.0.3",
"vfile-matter": "~5.0.0"
},
"devDependencies": {
"@eslint/compat": "^1.1.1",
"@next/eslint-plugin-next": "^14.2.8",
"@storybook/addon-controls": "~8.2.7",
"@storybook/addon-interactions": "~8.2.7",
"@storybook/addon-themes": "~8.2.7",
"@storybook/addon-viewport": "~8.2.7",
"@storybook/nextjs": "~8.2.7",
"@eslint/compat": "~1.1.1",
"@next/eslint-plugin-next": "~14.2.11",
"@storybook/addon-controls": "~8.3.0",
"@storybook/addon-interactions": "~8.3.0",
"@storybook/addon-themes": "~8.3.0",
"@storybook/addon-viewport": "~8.3.0",
"@storybook/nextjs": "~8.3.0",
"@testing-library/jest-dom": "~6.5.0",
"@testing-library/react": "~16.0.1",
"@testing-library/user-event": "~14.5.2",
"@types/jest": "29.5.12",
"@types/jest": "29.5.13",
"@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0",
"@types/semver": "~7.5.8",
"eslint": "^9.10.0",
"eslint-config-next": "~14.2.8",
"eslint-config-prettier": "9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import-x": "^4.2.1",
"eslint-plugin-mdx": "3.1.5",
"eslint-plugin-no-relative-import-paths": "^1.5.3",
"eslint-plugin-react": "^7.35.2",
"eslint-plugin-react-hooks": "5.1.0-rc.0",
"eslint-plugin-storybook": "0.9.0--canary.156.da7873a.0",
"eslint": "~9.10.0",
"eslint-config-next": "~14.2.11",
"eslint-import-resolver-typescript": "~3.6.3",
"eslint-plugin-import-x": "~4.2.1",
"eslint-plugin-mdx": "~3.1.5",
"eslint-plugin-no-relative-import-paths": "~1.5.5",
"eslint-plugin-react": "~7.36.1",
"eslint-plugin-react-hooks": "5.1.0-rc-4c58fce7-20240904",
"eslint-plugin-storybook": "0.9.0--canary.156.26b630a.0",
"handlebars": "4.7.8",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"jest-junit": "16.0.0",
"remark-frontmatter": "5.0.0",
"remark-preset-lint-node": "5.1.2",
"storybook": "~8.2.7",
"storybook": "~8.3.0",
"stylelint": "16.9.0",
"stylelint-config-standard": "36.0.1",
"stylelint-order": "6.0.4",
"stylelint-selector-bem-pattern": "4.0.0",
"typescript-eslint": "^8.4.0",
"stylelint-selector-bem-pattern": "4.0.1",
"typescript": "~5.5.4",
"typescript-eslint": "~8.5.0",
"user-agent-data-types": "0.4.2"
},
"overrides": {
"eslint": "$eslint"
}
}
Loading
Loading