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

46-standardize-page-template #52

Merged
merged 7 commits into from
Jul 5, 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
1,084 changes: 544 additions & 540 deletions package-lock.json

Large diffs are not rendered by default.

40 changes: 19 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"pre-commit": "node --run lint-all && node --run test && node --run bench"
},
"dependencies": {
"@hookform/resolvers": "^3.6.0",
"@hookform/resolvers": "^3.8.0",
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3",
"classnames": "^2.5.1",
Expand All @@ -42,50 +42,48 @@
"i18next-browser-languagedetector": "^8.0.0",
"luxon": "^3.4.4",
"react": "^18.3.1",
"react-bootstrap": "^2.10.2",
"react-bootstrap": "^2.10.4",
"react-dom": "^18.3.1",
"react-hook-form": "^7.51.5",
"react-hook-form": "^7.52.1",
"react-hotkeys-hook": "^4.5.0",
"react-i18next": "^14.1.2",
"react-router-dom": "^6.23.1",
"uuid": "^9.0.1",
"react-router-dom": "^6.24.1",
"workbox-cacheable-response": "^7.1.0",
"workbox-core": "^7.1.0",
"workbox-routing": "^7.1.0",
"workbox-strategies": "^7.1.0",
"workbox-window": "^7.1.0",
"zod": "^3.23.8",
"zustand": "^4.5.2"
"zustand": "^4.5.4"
},
"devDependencies": {
"@eslint/compat": "^1.0.3",
"@eslint/compat": "^1.1.0",
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.4.0",
"@eslint/js": "^9.6.0",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
"@types/bootstrap": "^5.2.10",
"@types/file-saver": "^2.0.7",
"@types/luxon": "^3.4.2",
"@types/node": "^20.14.2",
"@types/node": "^20.14.9",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^7.12.0",
"@typescript-eslint/parser": "^7.12.0",
"@vitejs/plugin-react": "^4.3.0",
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"@vitejs/plugin-react": "^4.3.1",
"@vitest/coverage-v8": "^1.6.0",
"esbuild": "^0.21.4",
"esbuild": "^0.23.0",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react": "^7.34.3",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"happy-dom": "^14.12.0",
"knip": "^5.18.0",
"happy-dom": "^14.12.3",
"knip": "^5.24.1",
"msw": "^2.3.1",
"prettier": "^3.3.1",
"sass": "^1.77.4",
"typescript": "^5.4.5",
"vite": "^5.2.13",
"prettier": "^3.3.2",
"sass": "^1.77.6",
"typescript": "^5.5.3",
"vite": "^5.3.3",
"vitest": "^1.5.0"
}
}
109 changes: 70 additions & 39 deletions scripts/find_i18n.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/* eslint-disable no-undef */
/* eslint-disable no-console */
import fs from 'node:fs';
import path from 'node:path';

const main = ({ locales, srcDir, ext, transDir }) => {
const findTokens = (srcDir, ext) => {
const tokens = new Set();
const source = path.resolve(srcDir);
const paths = fs.readdirSync(source, { recursive: true });

const SrcFullPath = path.join(import.meta.dirname, '../', srcDir);
const paths = fs.readdirSync(SrcFullPath, { recursive: true });
for (const relPath of paths) {
const absPath = path.join(source, relPath);
const absPath = path.join(SrcFullPath, relPath);
const stat = fs.statSync(absPath);
if (stat.isFile() && ext.some((it) => relPath.endsWith(it))) {
const content = fs.readFileSync(absPath, 'utf-8');
Expand All @@ -18,50 +19,80 @@ const main = ({ locales, srcDir, ext, transDir }) => {
}
}
}
return tokens;
};

const updateTranslates = (locale, fileFullPath, tokens) => {
let data = {};
try {
const content = fs.readFileSync(fileFullPath, 'utf-8');
data = JSON.parse(content);
} catch {
// ignore error
}

for (const locale of locales) {
let data = {};
const jsonFile = path.resolve(transDir, `${locale}.json`);
try {
const content = fs.readFileSync(jsonFile, 'utf-8');
data = JSON.parse(content);
} catch (err) {
// ignore error
if (!data.translation) {
data.translation = {};
}

const unknownTokens = [];
const addedTokens = [];
const noTranslatedTokens = [];
const translation = { ...data.translation };

for (const token of Object.keys(translation)) {
if (!tokens.has(token)) {
unknownTokens.push(token);
}
if (translation[token] === '' && translation[token] === token && locale !== 'en') {
noTranslatedTokens.push(token);
}
}

if (!data.translation) {
data.translation = {};
for (const token of tokens) {
if (translation[token] === undefined) {
addedTokens.push(token);
translation[token] = token;
}
}

const jsonData = data.translation;
const isUnknownTokens = unknownTokens.length > 0;
const isAddedTokens = addedTokens.length > 0;
const isNoTranslatedTokens = noTranslatedTokens.length > 0;

let showHeader = false;
for (const key of Object.keys(jsonData)) {
if (!tokens.has(key)) {
if (!showHeader) {
// eslint-disable-next-line no-console, no-undef
console.log(`Unknown tokens in file: ${jsonFile}`);
showHeader = true;
}
// eslint-disable-next-line no-console, no-undef
console.log(`"${key}"`);
}
if (isUnknownTokens || isAddedTokens || isNoTranslatedTokens) {
const separator = '-'.repeat(80);
console.log(separator);
console.log(`File: ${fileFullPath}`);
console.log(separator);
if (isUnknownTokens) {
console.log(`Unknown tokens: ${unknownTokens.join(', ')}`);
}
if (isAddedTokens) {
console.log(`Added tokens: ${addedTokens.join(', ')}`);
}
if (isNoTranslatedTokens) {
console.log(`No translated tokens: ${noTranslatedTokens.join(', ')}`);
}
}

let addedCount = 0;
if (isAddedTokens) {
data.translation = Object.keys(translation)
.sort()
.reduce((accum, key) => {
accum[key] = translation[key];
return accum;
}, {});

for (const key of tokens) {
if (!jsonData[key]) {
jsonData[key] = key;
addedCount++;
}
}
fs.writeFileSync(fileFullPath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
}
};

if (addedCount > 0) {
fs.writeFileSync(jsonFile, JSON.stringify(data, null, 2) + '\n', 'utf-8');
// eslint-disable-next-line no-console, no-undef
console.log(`Change file "${jsonFile}" - ${addedCount} added`);
}
const main = ({ locales, srcDir, ext, transDir }) => {
const tokens = findTokens(srcDir, ext);
for (const locale of locales) {
const fullPath = path.resolve(transDir, `${locale}.json`);
updateTranslates(locale, fullPath, tokens);
}
};

Expand Down
10 changes: 8 additions & 2 deletions src/components/Page/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,23 @@ import { ErrorBoundary } from './ErrorBoundary';

interface PageProps extends React.PropsWithChildren {
title: string;
hideTitle?: boolean;
}

export const Page = ({ title, children }: PageProps) => {
export const Page = ({ title, hideTitle, children }: PageProps) => {
useEffect(() => {
document.title = title;
}, [title]);

return (
<div className="container d-flex flex-column gap-4 min-vh-100">
<Header />
<ErrorBoundary>{children}</ErrorBoundary>
<ErrorBoundary>
<main className="d-flex flex-column flex-grow-1 justify-content-center align-items-center gap-3">
{!hideTitle && <h1 className="text-center">{title}</h1>}
{children}
</main>
</ErrorBoundary>
<Footer />
<UpdatePwaDialog />
</div>
Expand Down
1 change: 1 addition & 0 deletions src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ i18n
ru: transRu,
},
debug: import.meta.env.MODE === 'development',
supportedLngs: ['en', 'ru'],
fallbackLng: 'en',
});
Loading