diff --git a/client/app/i18n/index.js b/client/app/i18n/index.js new file mode 100644 index 0000000000..d285c50ed2 --- /dev/null +++ b/client/app/i18n/index.js @@ -0,0 +1,22 @@ +import i18n from "i18next"; +import LanguageDetector from "i18next-browser-languagedetector"; +import { initReactI18next } from "react-i18next"; +import en from "./locales/en.json"; +import zh from "./locales/zh.json"; + +i18n + .use(initReactI18next) + .use(LanguageDetector) + .init({ + resources: { + en: { translation: en }, + zh: { translation: zh }, + }, + fallbackLng: "zh", + preload: ["en", "zh"], + interpolation: { + escapeValue: false, + }, + }); + +export default i18n; diff --git a/client/app/i18n/locales/en.json b/client/app/i18n/locales/en.json new file mode 100644 index 0000000000..3c49bd5429 --- /dev/null +++ b/client/app/i18n/locales/en.json @@ -0,0 +1,3 @@ +{ + "dashboard": "dashboard" +} diff --git a/client/app/i18n/locales/zh.json b/client/app/i18n/locales/zh.json new file mode 100644 index 0000000000..f947fd472d --- /dev/null +++ b/client/app/i18n/locales/zh.json @@ -0,0 +1,4 @@ +{ + "dashboard": "看板", + "Favorite Dashboards": "收藏的看板" +} diff --git a/client/app/index.js b/client/app/index.js index 9cafdb1f4b..32e8a118f9 100644 --- a/client/app/index.js +++ b/client/app/index.js @@ -5,6 +5,7 @@ import "@/config"; import ApplicationArea from "@/components/ApplicationArea"; import offlineListener from "@/services/offline-listener"; +import "./i18n"; ReactDOM.render(, document.getElementById("application-root"), () => { offlineListener.init(); diff --git a/client/app/pages/home/components/FavoritesList.jsx b/client/app/pages/home/components/FavoritesList.jsx index 118930d679..54146ff183 100644 --- a/client/app/pages/home/components/FavoritesList.jsx +++ b/client/app/pages/home/components/FavoritesList.jsx @@ -7,6 +7,7 @@ import LoadingOutlinedIcon from "@ant-design/icons/LoadingOutlined"; import { Dashboard } from "@/services/dashboard"; import { Query } from "@/services/query"; +import { useTranslation } from "react-i18next"; export function FavoriteList({ title, resource, itemUrl, emptyState }) { const [items, setItems] = useState([]); @@ -53,13 +54,15 @@ FavoriteList.propTypes = { FavoriteList.defaultProps = { emptyState: null }; export function DashboardAndQueryFavoritesList() { + const { t } = useTranslation(); + return (
dashboard.url} emptyState={ diff --git a/package.json b/package.json index e84e4ef44f..233624a26e 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,8 @@ "font-awesome": "^4.7.0", "history": "^4.10.1", "hoist-non-react-statics": "^3.3.0", + "i18next": "^22.4.15", + "i18next-browser-languagedetector": "^7.0.1", "markdown": "0.5.0", "material-design-iconic-font": "^2.2.0", "moment": "^2.19.3", @@ -71,6 +73,7 @@ "react-ace": "^9.1.1", "react-dom": "^16.14.0", "react-grid-layout": "^0.18.2", + "react-i18next": "^12.2.2", "react-resizable": "^1.10.1", "react-virtualized": "^9.21.2", "sql-formatter": "git+https://github.com/getredash/sql-formatter.git", diff --git a/yarn.lock b/yarn.lock index 507aa2fc04..c084199e9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8129,6 +8129,20 @@ hyperlinker@^1.0.0: resolved "https://registry.yarnpkg.com/hyperlinker/-/hyperlinker-1.0.0.tgz#23dc9e38a206b208ee49bc2d6c8ef47027df0c0e" integrity sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ== +i18next-browser-languagedetector@^7.0.1: + version "7.0.2" + resolved "https://registry.npmmirror.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.2.tgz#22d8ed48411750c1a1828ac2031c816a5108e55f" + integrity sha512-5ViaK+gikxfqZ9M3jJ7gJkUzzu/p3HwiqfLoL1bdiL7CUb0IylcTyVLdPaTU3pH5VFWFCiGFuJDg3VkLUikWgg== + dependencies: + "@babel/runtime" "^7.19.4" + +i18next@^22.4.15: + version "22.5.1" + resolved "https://registry.npmmirror.com/i18next/-/i18next-22.5.1.tgz#99df0b318741a506000c243429a7352e5f44d424" + integrity sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA== + dependencies: + "@babel/runtime" "^7.20.6" + iconv-lite@0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" @@ -13060,6 +13074,14 @@ react-grid-layout@^0.18.2: react-draggable "^4.0.0" react-resizable "^1.9.0" +react-i18next@^12.2.2: + version "12.3.1" + resolved "https://registry.npmmirror.com/react-i18next/-/react-i18next-12.3.1.tgz#30134a41a2a71c61dc69c6383504929aed1c99e7" + integrity sha512-5v8E2XjZDFzK7K87eSwC7AJcAkcLt5xYZ4+yTPDAW1i7C93oOY1dnr4BaQM7un4Hm+GmghuiPvevWwlca5PwDA== + dependencies: + "@babel/runtime" "^7.20.6" + html-parse-stringify "^3.0.1" + react-is@^16.12.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"