I am making a website with some administration/hidden for regular user functionality. The application has internationalization. Main stack:
Next
next-i18next
NX
{
"name": "client",
"version": "1.0.0",
"license": "MIT",
"scripts": {
"serve": "nx serve",
"serve:prod": "nx serve --prod",
"build": "nx build",
"test": "nx test",
"eslint": "eslint --cache",
"prettier": "prettier --check --cache",
"lint": "nx lint",
"format": "nx format:check",
"e2e": "nx e2e",
"affected:e2e": "nx affected --target=e2e",
"affected:lint": "nx affected --target=lint",
"affected:format": "nx affected --target=format",
"affected:test": "nx affected --target=test",
"storybook": "nx storybook",
"storybook:build": "nx build-storybook",
"deploy": "vercel",
"deploy:prod": "vercel --prod",
"prepare": "husky install"
},
"private": true,
"dependencies": {
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@fontsource/roboto": "^4.5.7",
"@mui/base": "^5.0.0-alpha.91",
"@mui/icons-material": "^5.8.4",
"@mui/material": "^5.9.2",
"@reduxjs/toolkit": "^1.8.3",
"axios": "^0.27.2",
"formik": "^2.2.9",
"next": "^12.2.3",
"next-i18next": "^11.0.0",
"next-redux-wrapper": "^7.0.5",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-redux": "^8.0.2",
"vercel": "^27.1.3",
"yup": "^0.32.11"
},
"devDependencies": {
"@babel/core": "7.12.13",
"@babel/preset-typescript": "7.12.13",
"@commitlint/cli": "^17.0.3",
"@commitlint/config-conventional": "^17.0.3",
"@next/bundle-analyzer": "^12.2.3",
"@nrwl/cli": "14.4.2",
"@nrwl/cypress": "14.5.1",
"@nrwl/eslint-plugin-nx": "14.4.3",
"@nrwl/express": "^14.4.3",
"@nrwl/jest": "14.5.1",
"@nrwl/linter": "14.4.2",
"@nrwl/next": "14.4.0",
"@nrwl/node": "14.4.0",
"@nrwl/react": "14.4.2",
"@nrwl/storybook": "14.4.2",
"@nrwl/web": "14.4.3",
"@nrwl/workspace": "14.4.2",
"@storybook/addon-essentials": "~6.5.9",
"@storybook/builder-webpack5": "~6.5.9",
"@storybook/core-server": "~6.5.9",
"@storybook/manager-webpack5": "~6.5.9",
"@storybook/react": "~6.5.9",
"@svgr/webpack": "^5.4.0",
"@testing-library/cypress": "^8.0.3",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "13.3.0",
"@types/express": "4.17.13",
"@types/jest": "27.4.1",
"@types/node": "18.0.4",
"@types/react": "18.0.15",
"@types/react-dom": "18.0.5",
"@typescript-eslint/eslint-plugin": "^5.30.3",
"@typescript-eslint/parser": "^5.30.3",
"babel-jest": "27.5.1",
"babel-loader": "8.1.0",
"core-js": "^3.6.5",
"cypress": "^10.3.0",
"cypress-real-events": "^1.7.1",
"cypress-web-vitals": "^2.0.0",
"eslint": "8.2.0",
"eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-next": "12.1.6",
"eslint-config-prettier": "8.1.0",
"eslint-plugin-cypress": "^2.10.3",
"eslint-plugin-import": "2.25.3",
"eslint-plugin-jsx-a11y": "6.5.1",
"eslint-plugin-react": "7.30.1",
"eslint-plugin-react-hooks": "4.6.0",
"husky": "^8.0.1",
"jest": "27.5.1",
"lint-staged": "^13.0.3",
"nx": "14.5.1",
"prettier": "^2.7.1",
"react-test-renderer": "18.2.0",
"regenerator-runtime": "0.13.7",
"ts-jest": "27.1.4",
"ts-node": "~10.8.0",
"tslib": "^2.3.0",
"typescript": "~4.7.2",
"url-loader": "^3.0.0"
}
}
The problem is that raw locales in the .json
format are accessible by GET
requests. For example, I can visit http://localhost/locales/en/common.json
and get:
{
"email": {
"length": {
"short": "Email is too short",
"long": "Email is too long"
},
"format": "Email format is wrong",
"required": "Email is required"
},
"password": {
"length": {
"short": "Password is too short",
"long": "Password is too long"
},
"format": "Password format is wrong",
"required": "Password is required"
}
}
The locales are not placed in the public directory during development and next-i18next
is configured for another locales path by its next-i18next.config.js
.
const path = require('path');
module.exports = {
debug: process.env.NODE_ENV === 'development',
i18n: {
locales: ['en', 'uk'],
defaultLocale: 'en',
},
localePath: path.resolve('./apps/client/locales'),
};
I think that users can guess these paths and get some sensitive information. Are there any ways to make them accessible only for Next
, but not for the public? Maybe I should change my way of localization at all, shouldn't I?
next-translate looks like the library with different internationalization logic, which resolved my problem.