Skip to content

Commit

Permalink
chore: fix various intl stuff
Browse files Browse the repository at this point in the history
- remove intl-locales-supported & intl since they're deprecated and only
needed for IE11
- clean up babel intl extractor
- reset jest test timezone to UTC so it passes even for East Coast
contributor
  • Loading branch information
longlho committed Mar 12, 2021
1 parent ffe8b61 commit b89885a
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 119 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"lint:js": "eslint --cache \"**/*.{js,jsx,ts,tsx}\"",
"lint:style": "stylelint \"**/*.css\"",
"lerna": "lerna",
"test": "jest",
"test": "cross-env TZ=UTC jest",
"test:build:v2": "./admin/scripts/test-release.sh",
"watch": "yarn lerna run --parallel --no-private watch",
"clear": "yarn workspace docusaurus-2-website clear && yarn lerna exec --ignore docusaurus yarn rimraf lib",
Expand Down
14 changes: 5 additions & 9 deletions packages/docusaurus-plugin-content-blog/src/blogUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import {
getEditUrl,
getFolderContainingFile,
posixPath,
getDateTimeFormat,
} from '@docusaurus/utils';
import {LoadContext} from '@docusaurus/types';

Expand Down Expand Up @@ -175,14 +174,11 @@ export async function generateBlogPosts(

// Use file create time for blog.
date = date || (await fs.stat(source)).birthtime;
const formattedDate = getDateTimeFormat(i18n.currentLocale)(
i18n.currentLocale,
{
day: 'numeric',
month: 'long',
year: 'numeric',
},
).format(date);
const formattedDate = new Intl.DateTimeFormat(i18n.currentLocale, {
day: 'numeric',
month: 'long',
year: 'numeric',
}).format(date);

const slug =
frontMatter.slug || (match ? toUrl({date, link: linkName}) : linkName);
Expand Down
3 changes: 1 addition & 2 deletions packages/docusaurus-plugin-content-docs/src/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
normalizeUrl,
parseMarkdownString,
posixPath,
getDateTimeFormat,
} from '@docusaurus/utils';
import {LoadContext} from '@docusaurus/types';

Expand Down Expand Up @@ -212,7 +211,7 @@ export function processDocMetadata({
lastUpdatedBy: lastUpdate.lastUpdatedBy,
lastUpdatedAt: lastUpdate.lastUpdatedAt,
formattedLastUpdatedAt: lastUpdate.lastUpdatedAt
? getDateTimeFormat(i18n.currentLocale)(i18n.currentLocale).format(
? new Intl.DateTimeFormat(i18n.currentLocale).format(
lastUpdate.lastUpdatedAt * 1000,
)
: undefined,
Expand Down
3 changes: 2 additions & 1 deletion packages/docusaurus-theme-common/src/utils/usePluralForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ function useLocalePluralForms(): LocalePluralForms {
i18n: {currentLocale},
} = useDocusaurusContext();
return useMemo(() => {
if (Intl && Intl.PluralRules) {
// @ts-expect-error checking Intl.PluralRules in case browser doesn't have it (e.g Safari 12-)
if (Intl.PluralRules) {
try {
return createLocalePluralForms(currentLocale);
} catch (e) {
Expand Down
2 changes: 0 additions & 2 deletions packages/docusaurus-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
"escape-string-regexp": "^4.0.0",
"fs-extra": "^9.1.0",
"gray-matter": "^4.0.2",
"intl": "^1.2.5",
"intl-locales-supported": "1.8.11",
"lodash": "^4.17.20",
"resolve-pathname": "^3.0.0"
},
Expand Down
8 changes: 0 additions & 8 deletions packages/docusaurus-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {

// @ts-expect-error: no typedefs :s
import resolvePathnameUnsafe from 'resolve-pathname';
import areIntlLocalesSupported from 'intl-locales-supported';

const fileHash = new Map();
export async function generate(
Expand Down Expand Up @@ -634,13 +633,6 @@ export async function readDefaultCodeTranslationMessages({
return {};
}

export function getDateTimeFormat(locale: string) {
return areIntlLocalesSupported([locale])
? global.Intl.DateTimeFormat
: // eslint-disable-next-line @typescript-eslint/no-var-requires
require('intl').DateTimeFormat;
}

// Input: ## Some heading {#some-heading}
// Output: {text: "## Some heading", id: "some-heading"}
export function parseMarkdownHeadingId(
Expand Down
175 changes: 89 additions & 86 deletions packages/docusaurus/src/server/translations/translationsExtractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Need help understanding this?
Useful resources:
https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md
https://github.com/formatjs/formatjs/blob/main/packages/babel-plugin-react-intl/index.ts
https://github.com/formatjs/formatjs/blob/main/packages/babel-plugin-formatjs/index.ts
https://github.com/pugjs/babel-walk
*/
function extractSourceCodeAstTranslations(
Expand All @@ -190,20 +190,31 @@ function extractSourceCodeAstTranslations(

traverse(ast, {
JSXElement(path) {
if (
!path
.get('openingElement')
.get('name')
.isJSXIdentifier({name: 'Translate'})
) {
return;
}
function evaluateJSXProp(propName: string): string | undefined {
const attributePath = path
.get('openingElement.attributes')
.find(
(attr) => attr.isJSXAttribute() && attr.node.name.name === propName,
(attr) =>
attr.isJSXAttribute() &&
(attr as NodePath<t.JSXAttribute>)
.get('name')
.isJSXIdentifier({name: propName}),
);

if (attributePath) {
const attributeValue = attributePath.get('value') as NodePath;

const attributeValueEvaluated =
attributeValue.node.type === 'JSXExpressionContainer'
? (attributeValue.get('expression') as NodePath).evaluate()
: attributeValue.evaluate();
const attributeValueEvaluated = attributeValue.isJSXExpressionContainer()
? (attributeValue.get('expression') as NodePath).evaluate()
: attributeValue.evaluate();

if (
attributeValueEvaluated.confident &&
Expand All @@ -222,100 +233,92 @@ function extractSourceCodeAstTranslations(
return undefined;
}

if (
path.node.openingElement.name.type === 'JSXIdentifier' &&
path.node.openingElement.name.name === 'Translate'
// We only handle the optimistic case where we have a single non-empty content
const singleChildren = path
.get('children')
// Remove empty/useless text nodes that might be around our translation!
// Makes the translation system more reliable to JSX formatting issues
.filter(
(childrenPath) =>
!(
childrenPath.isJSXText() &&
childrenPath.node.value.replace('\n', '').trim() === ''
),
)
.pop();

if (singleChildren && singleChildren.isJSXText()) {
const message = singleChildren.node.value.trim().replace(/\s+/g, ' ');

const id = evaluateJSXProp('id');
const description = evaluateJSXProp('description');

translations[id ?? message] = {
message,
...(description && {description}),
};
} else if (
singleChildren &&
singleChildren.isJSXExpressionContainer() &&
(singleChildren.get('expression') as NodePath).evaluate().confident
) {
// We only handle the optimistic case where we have a single non-empty content
const singleChildren = path
.get('children')
// Remove empty/useless text nodes that might be around our translation!
// Makes the translation system more reliable to JSX formatting issues
.filter(
(childrenPath) =>
!(
t.isJSXText(childrenPath.node) &&
childrenPath.node.value.replace('\n', '').trim() === ''
),
)
.pop();

if (singleChildren && t.isJSXText(singleChildren.node)) {
const message = singleChildren.node.value.trim().replace(/\s+/g, ' ');

const id = evaluateJSXProp('id');
const description = evaluateJSXProp('description');

translations[id ?? message] = {
message,
...(description && {description}),
};
} else if (
singleChildren &&
t.isJSXExpressionContainer(singleChildren) &&
(singleChildren.get('expression') as NodePath).evaluate().confident
) {
const message = (singleChildren.get(
'expression',
) as NodePath).evaluate().value;

const id = evaluateJSXProp('id');
const description = evaluateJSXProp('description');

translations[id ?? message] = {
message,
...(description && {description}),
};
} else {
warnings.push(
`${staticTranslateJSXWarningPart}\n${sourceFileWarningPart(
path.node,
)}\n${generateCode(path.node)}`,
);
}
const message = (singleChildren.get(
'expression',
) as NodePath).evaluate().value;

const id = evaluateJSXProp('id');
const description = evaluateJSXProp('description');

translations[id ?? message] = {
message,
...(description && {description}),
};
} else {
warnings.push(
`${staticTranslateJSXWarningPart}\n${sourceFileWarningPart(
path.node,
)}\n${generateCode(path.node)}`,
);
}
},

CallExpression(path) {
if (
path.node.callee.type === 'Identifier' &&
path.node.callee.name === 'translate'
) {
// console.log('CallExpression', path.node);
if (
path.node.arguments.length === 1 ||
path.node.arguments.length === 2
) {
const firstArgPath = path.get('arguments.0') as NodePath;
if (!path.get('callee').isIdentifier({name: 'translate'})) {
return;
}

// evaluation allows translate("x" + "y"); to be considered as translate("xy");
const firstArgEvaluated = firstArgPath.evaluate();
// console.log('CallExpression', path.node);
const args = path.get('arguments');
if (args.length === 1 || args.length === 2) {
const firstArgPath = args[0];

// console.log('firstArgEvaluated', firstArgEvaluated);
// evaluation allows translate("x" + "y"); to be considered as translate("xy");
const firstArgEvaluated = firstArgPath.evaluate();

if (
firstArgEvaluated.confident &&
typeof firstArgEvaluated.value === 'object'
) {
const {message, id, description} = firstArgEvaluated.value;
translations[id ?? message] = {
message,
...(description && {description}),
};
} else {
warnings.push(
`translate() first arg should be a statically evaluable object.\nExample: translate({message: "text",id: "optional.id",description: "optional description"}\nDynamically constructed values are not allowed, because they prevent translations to be extracted.\n${sourceFileWarningPart(
path.node,
)}\n${generateCode(path.node)}`,
);
}
// console.log('firstArgEvaluated', firstArgEvaluated);

if (
firstArgEvaluated.confident &&
typeof firstArgEvaluated.value === 'object'
) {
const {message, id, description} = firstArgEvaluated.value;
translations[id ?? message] = {
message,
...(description && {description}),
};
} else {
warnings.push(
`translate() function only takes 1 or 2 args\n${sourceFileWarningPart(
`translate() first arg should be a statically evaluable object.\nExample: translate({message: "text",id: "optional.id",description: "optional description"}\nDynamically constructed values are not allowed, because they prevent translations to be extracted.\n${sourceFileWarningPart(
path.node,
)}\n${generateCode(path.node)}`,
);
}
} else {
warnings.push(
`translate() function only takes 1 or 2 args\n${sourceFileWarningPart(
path.node,
)}\n${generateCode(path.node)}`,
);
}
},
});
Expand Down
10 changes: 0 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10984,16 +10984,6 @@ interpret@^1.0.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==

intl-locales-supported@1.8.11:
version "1.8.11"
resolved "https://registry.yarnpkg.com/intl-locales-supported/-/intl-locales-supported-1.8.11.tgz#a8488b2998b524754e020fef0c0a67fa7b87bd5b"
integrity sha512-J+RhLNDxEvaNPdsoWz2KKlLSqU0MfV4Pd6zS1Yx/tN/KGN5QYe4Z2+ifJod95LlaA4K6qogwrSzm/WyTNOV6RA==

intl@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde"
integrity sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94=

into-stream@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6"
Expand Down

0 comments on commit b89885a

Please sign in to comment.