From 1a7188ff425bad19dfd364ace91cc1675b49ff73 Mon Sep 17 00:00:00 2001 From: "naoto.kido" Date: Mon, 24 Mar 2025 10:10:32 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20i18n=E3=81=AE=E3=83=99=E3=83=BC?= =?UTF-8?q?=E3=82=B9=E3=82=92=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .storybook/preview.ts | 14 ----- .storybook/preview.tsx | 25 +++++++++ app/components/Button/Button.stories.ts | 8 +-- app/components/Button/Button.tsx | 5 +- app/i18n/config.ts | 27 +++++++++ app/i18n/en.json | 10 ++++ app/i18n/ja.json | 10 ++++ app/root.tsx | 1 + package-lock.json | 75 ++++++++++++++++++++++++- package.json | 2 + 10 files changed, 155 insertions(+), 22 deletions(-) delete mode 100644 .storybook/preview.ts create mode 100644 .storybook/preview.tsx create mode 100644 app/i18n/config.ts create mode 100644 app/i18n/en.json create mode 100644 app/i18n/ja.json diff --git a/.storybook/preview.ts b/.storybook/preview.ts deleted file mode 100644 index cfa3024..0000000 --- a/.storybook/preview.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Preview } from '@storybook/react' - -const preview: Preview = { - parameters: { - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/i, - }, - }, - }, -}; - -export default preview; \ No newline at end of file diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx new file mode 100644 index 0000000..df9e0d8 --- /dev/null +++ b/.storybook/preview.tsx @@ -0,0 +1,25 @@ +import type { Preview } from '@storybook/react'; +import React from 'react'; +import { I18nextProvider } from 'react-i18next'; +import "../app/i18n/config"; +import i18n from '../app/i18n/config'; + +const preview: Preview = { + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + }, + decorators: [ + (Story) => ( + + + + ), + ], +}; + +export default preview; \ No newline at end of file diff --git a/app/components/Button/Button.stories.ts b/app/components/Button/Button.stories.ts index 2a05e01..c633593 100644 --- a/app/components/Button/Button.stories.ts +++ b/app/components/Button/Button.stories.ts @@ -28,26 +28,26 @@ type Story = StoryObj; export const Primary: Story = { args: { primary: true, - label: 'Button', + label: 'common.button', }, }; export const Secondary: Story = { args: { - label: 'Button', + label: 'common.button', }, }; export const Large: Story = { args: { size: 'large', - label: 'Button', + label: 'common.button', }, }; export const Small: Story = { args: { size: 'small', - label: 'Button', + label: 'common.button', }, }; diff --git a/app/components/Button/Button.tsx b/app/components/Button/Button.tsx index f35dafd..69ce3aa 100644 --- a/app/components/Button/Button.tsx +++ b/app/components/Button/Button.tsx @@ -1,5 +1,5 @@ -import React from 'react'; +import { useTranslation } from 'react-i18next'; import './button.css'; export interface ButtonProps { @@ -24,6 +24,7 @@ export const Button = ({ ...props }: ButtonProps) => { const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + const { t } = useTranslation(); return ( ); }; diff --git a/app/i18n/config.ts b/app/i18n/config.ts new file mode 100644 index 0000000..63002a5 --- /dev/null +++ b/app/i18n/config.ts @@ -0,0 +1,27 @@ +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; + +import translation_en from "./en.json"; +import translation_ja from "./ja.json"; + +const resources = { + ja: { + translation: translation_ja + }, + en: { + translation: translation_en + } + }; + + i18n + .use(initReactI18next) + .init({ + resources, + lng: "ja", + fallbackLng: "ja", + interpolation: { + escapeValue: false + } + }); + + export default i18n; \ No newline at end of file diff --git a/app/i18n/en.json b/app/i18n/en.json new file mode 100644 index 0000000..c99594b --- /dev/null +++ b/app/i18n/en.json @@ -0,0 +1,10 @@ +{ + "common": { + "button": "Button" + }, + "card": { + "memberCard": { + "stack": "Stacks" + } + } +} \ No newline at end of file diff --git a/app/i18n/ja.json b/app/i18n/ja.json new file mode 100644 index 0000000..b05ddd5 --- /dev/null +++ b/app/i18n/ja.json @@ -0,0 +1,10 @@ +{ + "common": { + "button": "ボタン" + }, + "card": { + "memberCard": { + "stack": "得意技術" + } + } +} \ No newline at end of file diff --git a/app/root.tsx b/app/root.tsx index 9fc6636..7257185 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -9,6 +9,7 @@ import { import type { Route } from "./+types/root"; import "./app.css"; +import "./i18n/config"; export const links: Route.LinksFunction = () => [ { rel: "preconnect", href: "https://fonts.googleapis.com" }, diff --git a/package-lock.json b/package-lock.json index c2071dc..26f74b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,11 @@ "dependencies": { "@react-router/node": "^7.3.0", "@react-router/serve": "^7.3.0", + "i18next": "^24.2.3", "isbot": "^5.1.17", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-i18next": "^15.4.1", "react-router": "^7.3.0" }, "devDependencies": { @@ -491,7 +493,6 @@ "version": "7.26.10", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz", "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", - "dev": true, "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -7493,6 +7494,15 @@ "dev": true, "license": "MIT" }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -7509,6 +7519,37 @@ "node": ">= 0.8" } }, + "node_modules/i18next": { + "version": "24.2.3", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-24.2.3.tgz", + "integrity": "sha512-lfbf80OzkocvX7nmZtu7nSTNbrTYR52sLWxPtlXX1zAhVw8WEnFk4puUkCR4B1dNQwbSpEHHHemcZu//7EcB7A==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.10" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -10004,6 +10045,28 @@ "react-dom": ">=16.8.1" } }, + "node_modules/react-i18next": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.4.1.tgz", + "integrity": "sha512-ahGab+IaSgZmNPYXdV1n+OYky95TGpFwnKRflX/16dY04DsYYKHtVLjeny7sBSCREEcoMbAgSkFiGLF5g5Oofw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -10320,7 +10383,6 @@ "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true, "license": "MIT" }, "node_modules/regexp.prototype.flags": { @@ -12613,6 +12675,15 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", diff --git a/package.json b/package.json index 8f91084..c1d4d28 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,11 @@ "dependencies": { "@react-router/node": "^7.3.0", "@react-router/serve": "^7.3.0", + "i18next": "^24.2.3", "isbot": "^5.1.17", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-i18next": "^15.4.1", "react-router": "^7.3.0" }, "devDependencies": {