diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ad446d6..2d4feda 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -87,5 +87,5 @@ yarn add @mui/icons-material
## react-i18next
```shell
-npm install react-i18next i18next --save
+yarn add react-i18next i18next
```
diff --git a/craco.config.js b/craco.config.js
index 22194c6..8ff8ac0 100644
--- a/craco.config.js
+++ b/craco.config.js
@@ -9,6 +9,7 @@ module.exports = {
'@images': path.resolve(__dirname, 'src/assets/images'),
'@components': path.resolve(__dirname, 'src/components'),
'@contexts': path.resolve(__dirname, 'src/contexts'),
+ '@locales': path.resolve(__dirname, 'src/locales'),
'@pages': path.resolve(__dirname, 'src/pages'),
'@store': path.resolve(__dirname, 'src/store'),
'@templates': path.resolve(__dirname, 'src/templates')
diff --git a/package.json b/package.json
index 456a894..c90f26e 100644
--- a/package.json
+++ b/package.json
@@ -20,8 +20,10 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^14.4.2",
+ "i18next": "^21.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-i18next": "^11.18.3",
"react-scripts": "5.0.1",
"recoil": "^0.7.4",
"web-vitals": "^2.1.4"
diff --git a/src/App.js b/src/App.js
index 7628b3a..56b2d4f 100644
--- a/src/App.js
+++ b/src/App.js
@@ -4,7 +4,7 @@ import { ThemeProvider, createTheme } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import { modeState } from "@store/theme";
import { ColorModeContext } from "@contexts/theme";
-import Page from "@pages";
+import Page from "@pages/home";
function App() {
const [mode, setMode] = useRecoilState(modeState);
diff --git a/src/components/header/ChangeLanguage.jsx b/src/components/header/ChangeLanguage.jsx
new file mode 100644
index 0000000..c9c4050
--- /dev/null
+++ b/src/components/header/ChangeLanguage.jsx
@@ -0,0 +1,36 @@
+import * as React from 'react';
+import { useRecoilState } from "recoil";
+import { useTranslation } from 'react-i18next';
+import MuiToggleButton from '@mui/material/ToggleButton';
+import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
+import { styled } from "@mui/material/styles";
+import { languageState } from "@store/theme";
+
+const ToggleButton = styled(MuiToggleButton)({
+ "&.Mui-selected, &.Mui-selected:hover": {
+ color: "white"
+ }
+});
+
+export default function ChangeLanguage() {
+ const { i18n } = useTranslation();
+ const [language, setLanguage] = useRecoilState(languageState);
+ const handleChangeLanguage = (event, newLanguage) => {
+ if (newLanguage) {
+ i18n.changeLanguage(newLanguage);
+ setLanguage(newLanguage);
+ }
+ };
+
+ return (
+
+ EN
+ KO
+
+ );
+}
diff --git a/src/components/header/MoreButton.jsx b/src/components/header/MoreActions.jsx
similarity index 85%
rename from src/components/header/MoreButton.jsx
rename to src/components/header/MoreActions.jsx
index b993aba..d6850bc 100644
--- a/src/components/header/MoreButton.jsx
+++ b/src/components/header/MoreActions.jsx
@@ -1,7 +1,7 @@
import IconButton from "@mui/material/IconButton";
import MoreIcon from "@mui/icons-material/MoreVert";
-export default function MoreButton() {
+export default function MoreActions() {
return (
diff --git a/src/components/main/CharactersLength.jsx b/src/components/main/CharactersLength.jsx
index 868cc46..b7a20a5 100644
--- a/src/components/main/CharactersLength.jsx
+++ b/src/components/main/CharactersLength.jsx
@@ -1,20 +1,22 @@
import * as React from "react";
+import { useTranslation } from "react-i18next";
import Typography from "@mui/material/Typography";
import Slider from "@mui/material/Slider";
export default function CharactersLength() {
+ const { t } = useTranslation();
+
return (
- Characters Length: 0 - 9
+ {t("characters length")}: 10
"Temperature range"}
- // value={value}
- // onChange={handleChange}
+ defaultValue={10}
+ aria-label="Small"
valueLabelDisplay="auto"
- // getAriaValueText={valuetext}
- disableSwap
+ min={0}
+ max={20}
/>
);
diff --git a/src/components/main/CharactersUsed.jsx b/src/components/main/CharactersUsed.jsx
index ae5ebf3..4a076a6 100644
--- a/src/components/main/CharactersUsed.jsx
+++ b/src/components/main/CharactersUsed.jsx
@@ -1,14 +1,17 @@
import * as React from "react";
+import { useTranslation } from "react-i18next";
import Typography from "@mui/material/Typography";
import FormGroup from "@mui/material/FormGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import Checkbox from "@mui/material/Checkbox";
export default function CharactersUsed() {
+ const { t } = useTranslation();
+
return (
- Characters Used:
+ {t("characters used")}:
- Input
+ {t("input")}
- Output
+ {t("output")}
diff --git a/src/components/main/RandomWords.jsx b/src/components/main/RandomWord.jsx
similarity index 75%
rename from src/components/main/RandomWords.jsx
rename to src/components/main/RandomWord.jsx
index 3d7ac0f..ed25243 100644
--- a/src/components/main/RandomWords.jsx
+++ b/src/components/main/RandomWord.jsx
@@ -1,15 +1,18 @@
import * as React from "react";
+import { useTranslation } from "react-i18next";
import Switch from "@mui/material/Switch";
import Divider from "@mui/material/Divider";
import CharactersUsed from "@components/main/CharactersUsed";
import CharactersLength from "@components/main/CharactersLength";
import StopWords from "@components/main/StopWords";
-export default function RandomWords() {
+export default function RandomWord() {
+ const { t } = useTranslation();
+
return (
- Random Words
+ {t("random word")}
diff --git a/src/components/main/Settings.jsx b/src/components/main/Settings.jsx
index e60d2ea..819b87a 100644
--- a/src/components/main/Settings.jsx
+++ b/src/components/main/Settings.jsx
@@ -1,42 +1,45 @@
import * as React from "react";
+import { useTranslation } from "react-i18next";
import Typography from "@mui/material/Typography";
import Grid from "@mui/material/Grid";
import TextField from "@mui/material/TextField";
import Switch from "@mui/material/Switch";
-import RandomWords from "@components/main/RandomWords";
+import RandomWord from "@components/main/RandomWord";
export default function Settings() {
+ const { t } = useTranslation();
+
return (
- Customize Prefix and Suffix
+ {t("set additional string")}
- Prefix
+ {t("prepend to string")}
-
+
- Suffix
+ {t("append after string")}
-
+
diff --git a/src/components/main/StopWords.jsx b/src/components/main/StopWords.jsx
index 275be14..31c1bfc 100644
--- a/src/components/main/StopWords.jsx
+++ b/src/components/main/StopWords.jsx
@@ -1,20 +1,23 @@
import * as React from "react";
+import { useTranslation } from "react-i18next";
import Typography from "@mui/material/Typography";
import TextField from "@mui/material/TextField";
export default function StopWords() {
+ const { t } = useTranslation();
+
return (
- Stop Words:
+ {t("stop words")}:
);
diff --git a/src/index.js b/src/index.js
index 2822138..35c3f3a 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,9 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
-import '@css/App.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { RecoilRoot } from "recoil";
+import '@locales/i18n';
+import '@css/App.css';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
new file mode 100644
index 0000000..6d90bfc
--- /dev/null
+++ b/src/locales/en/translation.json
@@ -0,0 +1,15 @@
+{
+ "title": "Smart Shuffle Words",
+ "input": "Input",
+ "output": "Output",
+ "shuffle & copy": "Shuffle & Copy",
+ "set additional string": "Set additional string",
+ "prepend to string": "Prepend to string",
+ "append after string": "Append after string",
+ "random word": "Random Word",
+ "characters used": "Characters Used",
+ "characters length": "Characters Length",
+ "stop words": "Stop Words",
+ "please enter text": "Please enter text",
+ "seperated by comma": "Seperated by comma"
+}
diff --git a/src/locales/i18n.js b/src/locales/i18n.js
new file mode 100644
index 0000000..0bdfc11
--- /dev/null
+++ b/src/locales/i18n.js
@@ -0,0 +1,36 @@
+import i18n from "i18next";
+import { initReactI18next } from "react-i18next";
+import translationEn from "@locales/en/translation";
+import translationKo from "@locales/ko/translation";
+
+i18n
+ .use(initReactI18next) // passes i18n down to react-i18next
+ .init({
+ // the translations
+ // (tip move them in a JSON file and import them,
+ // or even better, manage them via a UI: https://react.i18next.com/guides/multiple-translation-files#manage-your-translations-with-a-management-gui)
+ resources: {
+ en: {
+ translations: translationEn
+ },
+ ko: {
+ translations: translationKo
+ }
+ },
+
+ lng: "ko", // if you're using a language detector, do not define the lng option
+ fallbackLng: "ko",
+
+ ns: "translations", // string or array of namespaces to load
+ defaultNS: "translations", // default namespace used if not passed to the translation function
+
+ // char to separate keys. If working with a flat JSON,
+ // it's recommended to set this to false.
+ keySeparator: false, // (default) '.'
+
+ interpolation: {
+ escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
+ }
+ });
+
+ export default i18n;
diff --git a/src/locales/ko/translation.json b/src/locales/ko/translation.json
new file mode 100644
index 0000000..c108990
--- /dev/null
+++ b/src/locales/ko/translation.json
@@ -0,0 +1,15 @@
+{
+ "title": "스마트 셔플 워드",
+ "input": "상품명",
+ "output": "상품명 수정",
+ "shuffle & copy": "상품명 변경 후 자동 복사",
+ "set additional string": "추가 문자열 설정",
+ "prepend to string": "문자열 앞에 추가",
+ "append after string": "문자열 뒤에 추가",
+ "random word": "무작위 단어",
+ "characters used": "사용된 문자",
+ "characters length": "문자 길이",
+ "stop words": "금칙어",
+ "please enter text": "텍스트를 입력 하십시오",
+ "seperated by comma": "쉼표로 구분 합니다"
+}
diff --git a/src/pages/index.jsx b/src/pages/home.jsx
similarity index 100%
rename from src/pages/index.jsx
rename to src/pages/home.jsx
diff --git a/src/store/theme.js b/src/store/theme.js
index b6ae863..464028a 100644
--- a/src/store/theme.js
+++ b/src/store/theme.js
@@ -2,5 +2,10 @@ import { atom } from "recoil";
export const modeState = atom({
key: "modeState",
- default: 'light'
+ default: "light",
+});
+
+export const languageState = atom({
+ key: "languageState",
+ default: "ko",
});
diff --git a/src/templates/Header.jsx b/src/templates/Header.jsx
index c50930e..07f3e92 100644
--- a/src/templates/Header.jsx
+++ b/src/templates/Header.jsx
@@ -1,18 +1,23 @@
+import { useTranslation } from "react-i18next";
import AppBar from "@mui/material/AppBar";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
import ToggleColorMode from "@components/header/ToggleColorMode";
-import MoreButton from '@components/header/MoreButton';
+import ChangeLanguage from "@components/header/ChangeLanguage";
+// import MoreActions from "@components/header/MoreActions";
export default function Header() {
+ const { t } = useTranslation();
+
return (
- Smart Shuffle Words
+ {t("title")}
-
+
+ {/* */}
);
diff --git a/yarn.lock b/yarn.lock
index 1251dd3..ee024e5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1035,7 +1035,7 @@
core-js-pure "^3.20.2"
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
+"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
@@ -5495,6 +5495,13 @@ html-minifier-terser@^6.0.2:
relateurl "^0.2.7"
terser "^5.10.0"
+html-parse-stringify@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
+ integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
+ dependencies:
+ void-elements "3.1.0"
+
html-webpack-plugin@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50"
@@ -5618,6 +5625,13 @@ humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"
+i18next@^21.9.0:
+ version "21.9.0"
+ resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.9.0.tgz#b63ebb0d4e1b23709951ca4774dc19d2ffac9553"
+ integrity sha512-B+6/yd7rCpJidyPuBaEApUECx7G8Ai6+tqYhrChsY4MmQqJhG7qJ4eT6Lm1OnRhieVelEtfxh4aAQktdNVZtDA==
+ dependencies:
+ "@babel/runtime" "^7.17.2"
+
iconv-lite@0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -8585,6 +8599,14 @@ react-error-overlay@^6.0.11:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb"
integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==
+react-i18next@^11.18.3:
+ version "11.18.3"
+ resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.18.3.tgz#50211810bcc9fdea2d70c8aefdfff5f1eb39a923"
+ integrity sha512-EttTX31HbqzZymUM3SIrMPuvamfSXFZVsDHm/ZAqoDfTLjhzlwyxqfbDNxcKNAGOi2mjZaXfR7hSNMlvLNpB/g==
+ dependencies:
+ "@babel/runtime" "^7.14.5"
+ html-parse-stringify "^3.0.1"
+
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@@ -10101,6 +10123,11 @@ vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+void-elements@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
+ integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
+
w3c-hr-time@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"