diff --git a/package-lock.json b/package-lock.json index 43b4fcd..828cf2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,15 +9,15 @@ "version": "1.0.2", "dependencies": { "@kintone/rest-api-client": "^5.7.4", - "angular-expressions": "^1.4.3", "clsx": "^2.1.1", - "dayjs": "^1.11.13", + "i18next": "^25.3.0", "immer": "^10.1.1", "moize": "^6.1.6", "nanoid": "^5.1.5", "react": "^19.1.0", "react-dom": "^19.1.0", "react-error-boundary": "^6.0.0", + "react-i18next": "^15.6.0", "tiny-invariant": "^1.3.3" }, "devDependencies": { @@ -25,8 +25,8 @@ "@kintone/dts-gen": "^8.1.2", "@kintone/plugin-uploader": "^9.1.5", "@kintone/webpack-plugin-kintone-plugin": "^8.0.11", - "@rspack/cli": "^1.4.2", - "@rspack/core": "^1.4.2", + "@rspack/cli": "^1.4.3", + "@rspack/core": "^1.4.3", "@shin-chan/kypes": "^0.0.7", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", @@ -1149,28 +1149,28 @@ } }, "node_modules/@rspack/binding": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.4.2.tgz", - "integrity": "sha512-NdTLlA20ufD0thFvDIwwPk+bX9yo3TDE4XjfvZYbwFyYvBgqJOWQflnbwLgvSTck0MSTiOqWIqpR88ymAvWTqg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.4.3.tgz", + "integrity": "sha512-bDKAruEbEdlozi8NkLrC0H+e/CfWuQgxi08akofLBp227Nd/n0yLF4VWaUkZr4lSbMJQBxXPattryDijDnoLwA==", "dev": true, "license": "MIT", "optionalDependencies": { - "@rspack/binding-darwin-arm64": "1.4.2", - "@rspack/binding-darwin-x64": "1.4.2", - "@rspack/binding-linux-arm64-gnu": "1.4.2", - "@rspack/binding-linux-arm64-musl": "1.4.2", - "@rspack/binding-linux-x64-gnu": "1.4.2", - "@rspack/binding-linux-x64-musl": "1.4.2", - "@rspack/binding-wasm32-wasi": "1.4.2", - "@rspack/binding-win32-arm64-msvc": "1.4.2", - "@rspack/binding-win32-ia32-msvc": "1.4.2", - "@rspack/binding-win32-x64-msvc": "1.4.2" + "@rspack/binding-darwin-arm64": "1.4.3", + "@rspack/binding-darwin-x64": "1.4.3", + "@rspack/binding-linux-arm64-gnu": "1.4.3", + "@rspack/binding-linux-arm64-musl": "1.4.3", + "@rspack/binding-linux-x64-gnu": "1.4.3", + "@rspack/binding-linux-x64-musl": "1.4.3", + "@rspack/binding-wasm32-wasi": "1.4.3", + "@rspack/binding-win32-arm64-msvc": "1.4.3", + "@rspack/binding-win32-ia32-msvc": "1.4.3", + "@rspack/binding-win32-x64-msvc": "1.4.3" } }, "node_modules/@rspack/binding-darwin-arm64": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.4.2.tgz", - "integrity": "sha512-0fPOew7D0l/x6qFZYdyUqutbw15K98VLvES2/7x2LPssTgypE4rVmnQSmVBnge3Nr8Qs/9qASPRpMWXBaqMfOA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.4.3.tgz", + "integrity": "sha512-YwPYWvo+WhdQgb76ZnH6m4sXClcRJJ5UB3Qj7xABKDQNJ62MaczWHEPfh2LM4iSJ1IWMo9dW4yeEXa7U9aE94w==", "cpu": [ "arm64" ], @@ -1182,9 +1182,9 @@ ] }, "node_modules/@rspack/binding-darwin-x64": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.4.2.tgz", - "integrity": "sha512-0Dh6ssGgwnd9G+IO8SwQaJ0RJ8NkQbk4hwoJH/u52Mnfl0EvhmNvuhkbSEoKn1U3kElOA2cxH/3gbYzuYExn3g==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.4.3.tgz", + "integrity": "sha512-aynWl0uCfIVfzDiZtSA6l75U8zyIc0UBa0p/ZETHrIQlBHPKDmxVIOlpbJWprilw5i4a3nWbadKCzvb0Gb92iA==", "cpu": [ "x64" ], @@ -1196,9 +1196,9 @@ ] }, "node_modules/@rspack/binding-linux-arm64-gnu": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.4.2.tgz", - "integrity": "sha512-UHAzggS8Mc7b3Xguhj82HwujLqBZquCeo8qJj5XreNaMKGb6YRw/91dJOVmkNiLCB0bj71CRE1Cocd+Peq3N9A==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.4.3.tgz", + "integrity": "sha512-x6OlSqt4esxj5hAZq+aPSG1pbNtjLPDw3cnQlfqv04kJO6MOwrH+j4DPc+/Q2qKdFzLw807eyvKd3O9leu+iPg==", "cpu": [ "arm64" ], @@ -1210,9 +1210,9 @@ ] }, "node_modules/@rspack/binding-linux-arm64-musl": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.4.2.tgz", - "integrity": "sha512-QybZ0VxlFih+upLoE7Le5cN3LpxJwk6EnEQTigmzpfc4c4SOC889ftBoIAO3IeBk+mF3H2C9xD+/NolTdwoeiw==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.4.3.tgz", + "integrity": "sha512-6aCa76fW8WlSBc0bJKXLSql79NoFlua4b+59XN1kZln+yLstgicFiJSvAnw+9U7mrl7IP9UmVWTw3JBnHUtw4A==", "cpu": [ "arm64" ], @@ -1224,9 +1224,9 @@ ] }, "node_modules/@rspack/binding-linux-x64-gnu": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.4.2.tgz", - "integrity": "sha512-ucCCWdtH1tekZadrsYj6GNJ8EP21BM2uSE7MootbwLw8aBtgVTKUuRDQEps1h/rtrdthzd9XBX6Lc2N926gM+g==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.4.3.tgz", + "integrity": "sha512-N2kUPPVjkky9KlK/a1QXvRivtTS0RJ1ZGRfkacycOTcKwB3nvrz6IqYOFhIst9Wjed677KELKP5zZv/VImfY7Q==", "cpu": [ "x64" ], @@ -1238,9 +1238,9 @@ ] }, "node_modules/@rspack/binding-linux-x64-musl": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.4.2.tgz", - "integrity": "sha512-+Y2LS6Qyk2AZor8DqlA8yKCqElYr0Urjc3M66O4ZzlxDT5xXX0J2vp04AtFp0g81q/+UgV3cbC//dqDvO0SiBA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.4.3.tgz", + "integrity": "sha512-SAzoCLCHQMFoQ41i9APIfE2ndv3JT5LkPvl6V1FmiFRgZwH0jVKpIybulZtgLNgNh4nFIYES0+2XK8dZ28YR5g==", "cpu": [ "x64" ], @@ -1252,9 +1252,9 @@ ] }, "node_modules/@rspack/binding-wasm32-wasi": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.4.2.tgz", - "integrity": "sha512-3WvfHY7NvzORek3FcQWLI/B8wQ7NZe0e0Bub9GyLNVxe5Bi+dxnSzEg6E7VsjbUzKnYufJA0hDKbEJ2qCMvpdw==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.4.3.tgz", + "integrity": "sha512-jrakte9rA3a+VfRqm4Qa3o+MI4lfYZGqQTdpWyC9GLi3USxyaU55hGYdd/TtGvDY82KvJfGTV8o+LRn0Pl77OA==", "cpu": [ "wasm32" ], @@ -1266,9 +1266,9 @@ } }, "node_modules/@rspack/binding-win32-arm64-msvc": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.4.2.tgz", - "integrity": "sha512-Y6L9DrLFRW6qBBCY3xBt7townStN5mlcbBTuG1zeXl0KcORPv1G1Cq6HXP6f1em+YsHE1iwnNqLvv4svg5KsnQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.4.3.tgz", + "integrity": "sha512-Tho05w0sUWKe7avQYYGwaL5xNDFRav4A4Su5DTCC6mQeokbndg0Lk7jtyYIp9ZHCStUOojR4PY/4zG918ky95w==", "cpu": [ "arm64" ], @@ -1280,9 +1280,9 @@ ] }, "node_modules/@rspack/binding-win32-ia32-msvc": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.4.2.tgz", - "integrity": "sha512-FyTJrL7GcYXPWKUB9Oj2X29kfma6MUgM9PyXGy8gDMti21kMMhpHp/bGVqfurRbazDyklDuLLtbHuawpa6toeA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.4.3.tgz", + "integrity": "sha512-Hc8tC30FvW5h8r3wW7C0pqY5b5BlMk0Y7vi03Zt60r8WqmeNINvAsjzyifHikD4S4lyQQO4CGXZOzSBWUcYesw==", "cpu": [ "ia32" ], @@ -1294,9 +1294,9 @@ ] }, "node_modules/@rspack/binding-win32-x64-msvc": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.4.2.tgz", - "integrity": "sha512-ODSU26tmG8MfMFDHCaMLCORB64EVdEtDvPP5zJs0Mgh7vQaqweJtqgG0ukZCQy4ApUatOrMaZrLk557jp9Biyw==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.4.3.tgz", + "integrity": "sha512-D+I6fl6Phq8+VElvf3sVTh+bqatk9Rjtgh4l2D7elIUkBguT5nAY3SX5wE/7iYnSdOBbP5mghU4exOG7NYqJYA==", "cpu": [ "x64" ], @@ -1308,9 +1308,9 @@ ] }, "node_modules/@rspack/cli": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/cli/-/cli-1.4.2.tgz", - "integrity": "sha512-S1d82mOdL0Iio/KoJ8E8HRAamBqpfvePZ+qkffs2sAYEzLrBQyI8dEADJ5SXPoHdyy8IafcrlRJnBh0ETLVVsg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/cli/-/cli-1.4.3.tgz", + "integrity": "sha512-6OLbIL5TxVsAiWjx7MZvA8hq7fz1m8rPDuvB9QhvpEFIpL3OqZf0+LTY60ApOFOSy+/vYWFe0oT+8NGOX65RjA==", "dev": true, "license": "MIT", "dependencies": { @@ -1331,14 +1331,14 @@ } }, "node_modules/@rspack/core": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.4.2.tgz", - "integrity": "sha512-Mmk3X3fbOLtRq4jX8Ebp3rfjr75YgupvNksQb0WbaGEVr5l1b6woPH/LaXF2v9U9DP83wmpZJXJ8vclB5JfL/w==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.4.3.tgz", + "integrity": "sha512-zWdAXleiYZ+SlappgDbjsoBWIQzyYJX5WwPXmoQnHJPb4K+zmjCL8MRfdIMIxXcg5IiQsBfiWY/lYhaZ2Jc0EA==", "dev": true, "license": "MIT", "dependencies": { "@module-federation/runtime-tools": "0.15.0", - "@rspack/binding": "1.4.2", + "@rspack/binding": "1.4.3", "@rspack/lite-tapable": "1.0.1" }, "engines": { @@ -2556,12 +2556,6 @@ "ajv": "^8.8.2" } }, - "node_modules/angular-expressions": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/angular-expressions/-/angular-expressions-1.4.3.tgz", - "integrity": "sha512-r7j+dqOuHy0OYiR5AazDixU/Us3TDN2FfuxGX4Dq6d61Y2MhBQHMdUNBfkkLPjDqVm2Is394h31gC3bcBwy9zw==", - "license": "Unlicense" - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -3803,12 +3797,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dayjs": { - "version": "1.11.13", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", - "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", - "license": "MIT" - }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", @@ -4648,14 +4636,13 @@ } }, "node_modules/eslint-plugin-n": { - "version": "17.20.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.20.0.tgz", - "integrity": "sha512-IRSoatgB/NQJZG5EeTbv/iAx1byOGdbbyhQrNvWdCfTnmPxUT0ao9/eGOeG7ljD8wJBsxwE8f6tES5Db0FRKEw==", + "version": "17.21.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.21.0.tgz", + "integrity": "sha512-1+iZ8We4ZlwVMtb/DcHG3y5/bZOdazIpa/4TySo22MLKdwrLcfrX0hbadnCvykSQCCmkAnWmIP8jZVb2AAq29A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.5.0", - "@typescript-eslint/utils": "^8.26.1", "enhanced-resolve": "^5.17.1", "eslint-plugin-es-x": "^7.8.0", "get-tsconfig": "^4.8.1", @@ -5905,6 +5892,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-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -6024,6 +6020,37 @@ "node": ">=10.18" } }, + "node_modules/i18next": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.3.0.tgz", + "integrity": "sha512-ZSQIiNGfqSG6yoLHaCvrkPp16UejHI8PCDxFYaNG/1qxtmqNmqEg4JlWKlxkrUmrin2sEjsy+Mjy1TRozBhOgw==", + "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.27.6" + }, + "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", @@ -8562,6 +8589,32 @@ "react": ">=16.13.1" } }, + "node_modules/react-i18next": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.6.0.tgz", + "integrity": "sha512-W135dB0rDfiFmbMipC17nOhGdttO5mzH8BivY+2ybsQBbXvxWIwl3cmeH3T9d+YPBSJu/ouyJKFJTtkK7rJofw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -10501,7 +10554,7 @@ "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -10713,6 +10766,15 @@ "node": ">= 0.8" } }, + "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/watchpack": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", diff --git a/package.json b/package.json index 4e02046..fc3badf 100644 --- a/package.json +++ b/package.json @@ -15,15 +15,15 @@ }, "dependencies": { "@kintone/rest-api-client": "^5.7.4", - "angular-expressions": "^1.4.3", "clsx": "^2.1.1", - "dayjs": "^1.11.13", + "i18next": "^25.3.0", "immer": "^10.1.1", "moize": "^6.1.6", "nanoid": "^5.1.5", "react": "^19.1.0", "react-dom": "^19.1.0", "react-error-boundary": "^6.0.0", + "react-i18next": "^15.6.0", "tiny-invariant": "^1.3.3" }, "devDependencies": { @@ -31,8 +31,8 @@ "@kintone/dts-gen": "^8.1.2", "@kintone/plugin-uploader": "^9.1.5", "@kintone/webpack-plugin-kintone-plugin": "^8.0.11", - "@rspack/cli": "^1.4.2", - "@rspack/core": "^1.4.2", + "@rspack/cli": "^1.4.3", + "@rspack/core": "^1.4.3", "@shin-chan/kypes": "^0.0.7", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", diff --git a/src/common/config.ts b/src/common/config.ts index c681349..82b3739 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -18,6 +18,7 @@ const decodeConfigLookup = (lookup: string): PluginConfigLookup | null => { try { return JSON.parse(lookup) as PluginConfigLookup; } catch (e) { + console.error('Failed to decode config lookup:', e); return null; } }; diff --git a/src/common/context.ts b/src/common/context.ts index 1e05331..3929bce 100644 --- a/src/common/context.ts +++ b/src/common/context.ts @@ -22,20 +22,20 @@ const filterLookupFields = (properties: KintoneFormFieldProperties): KintoneForm .sort((a, b) => naturalCompare(`${a.label} (${a.code})`, `${b.label} (${b.code})`)); }; -const getFormFieldsProperties = async (appId: KintoneAppId): Promise => { +const getFormFieldsProperties = async (appId: KintoneAppId, preview: boolean): Promise => { const client = new KintoneRestAPIClient(); - const { properties } = await client.app.getFormFields({ app: appId, lang: 'en', preview: false }); + const { properties } = await client.app.getFormFields({ app: appId, preview }); return properties; }; -export const getPluginContext = async (appId: KintoneAppId): Promise => { +export const getPluginContext = async (appId: KintoneAppId, isConfig: boolean): Promise => { const context: PluginContext = { appId: appId, formFieldsProperties: {}, attachmentFields: {}, lookupFields: [], }; - const properties = await getFormFieldsProperties(appId); + const properties = await getFormFieldsProperties(appId, isConfig); context.formFieldsProperties[appId] = properties; context.attachmentFields[appId] = filterAttachmentFields(properties); const lookupFields = filterLookupFields(properties); @@ -44,7 +44,7 @@ export const getPluginContext = async (appId: KintoneAppId): Promise self.indexOf(value) === index); await Promise.all( relatedAppIds.map(async (relatedAppId) => { - const relatedProperties = await getFormFieldsProperties(relatedAppId); + const relatedProperties = await getFormFieldsProperties(relatedAppId, false); context.formFieldsProperties[relatedAppId] = relatedProperties; context.attachmentFields[relatedAppId] = filterAttachmentFields(relatedProperties); }), diff --git a/src/common/kintoneLanguageDetector.ts b/src/common/kintoneLanguageDetector.ts new file mode 100644 index 0000000..c9c5abd --- /dev/null +++ b/src/common/kintoneLanguageDetector.ts @@ -0,0 +1,10 @@ +import { LanguageDetectorModule } from 'i18next'; + +const KintoneLanguageDetector: LanguageDetectorModule = { + type: 'languageDetector', + // init: () => {}, + detect: () => kintone.getLoginUser().language, + // cacheUserLanguage: () => {}, +}; + +export default KintoneLanguageDetector; diff --git a/src/common/kintoneUtils.ts b/src/common/kintoneUtils.ts deleted file mode 100644 index 7cd9920..0000000 --- a/src/common/kintoneUtils.ts +++ /dev/null @@ -1,9 +0,0 @@ -import invariant from 'tiny-invariant'; - -const KintoneUserLanguages = ['en', 'ja', 'zh', 'zh-TW', 'es', 'pt-BR', 'th'] as const; -export type KintoneUserLanguages = (typeof KintoneUserLanguages)[number]; -export const LANGUAGE = kintone.getLoginUser().language as KintoneUserLanguages; -invariant( - KintoneUserLanguages.includes(LANGUAGE), - `Unsupported language: ${LANGUAGE}. Supported languages are: ${KintoneUserLanguages.join(', ')}`, -); diff --git a/src/config/Settings.tsx b/src/config/Settings.tsx index 2c980eb..0912a17 100644 --- a/src/config/Settings.tsx +++ b/src/config/Settings.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { produce } from 'immer'; +import moize from 'moize'; +import { useTranslation } from 'react-i18next'; import invariant from 'tiny-invariant'; import { loadPluginConfigLookup, @@ -21,7 +23,6 @@ import KintonePluginTableTd from '../common/ui/KintonePluginTableTd'; import KintonePluginTableTh from '../common/ui/KintonePluginTableTh'; import KintonePluginTitle from '../common/ui/KintonePluginTitle'; -import moize from 'moize'; import styles from './Settings.module.css'; const hasDuplicate = (items: T[], func: (a: T, b: T) => boolean = (a, b) => a === b): boolean => { @@ -151,9 +152,10 @@ interface SettingsProps { const Settings: React.FC = (props) => { const { pluginId } = props; + const { t } = useTranslation(); const appId = kintone.app.getId(); invariant(appId, 'The app ID is not available. Please ensure you are on a Kintone app page.'); - const context = React.use(cachedPluginContext(appId)); + const context = React.use(cachedPluginContext(appId, true)); const [mappings, setMappings] = React.useState( () => @@ -212,13 +214,13 @@ const Settings: React.FC = (props) => { const handleOnSubmit = (e: React.FormEvent) => { e.preventDefault(); if (mappings.find((item) => item.destAttachmentFieldCode === '') != null) { - setError('Incomplete field mapping found'); + setError(t('settings.lookup.errors.incomplete-field-mapping-found')); } else if (hasDuplicateDestAttachmentFields(mappings)) { - setError('Same destination attachment fields found'); + setError(t('settings.lookup.errors.same-destination-attachment-field-found')); } else { setError(''); savePluginConfigLookup(mappings, () => { - alert('The plug-in settings have been saved. Please update the app!'); + alert(t('on-saved')); window.location.href = `../../flow?app=${appId}`; }); } @@ -231,7 +233,7 @@ const Settings: React.FC = (props) => { return (
- Settings for the Kintone Lookup File Sync plugin + {t('title')} {error !== '' && ( {error} @@ -240,22 +242,25 @@ const Settings: React.FC = (props) => {
- Field Mappings* + {t('settings.lookup.title')} + * - - Select lookup and attachment fields that used for the file synchronization. - + {t('settings.lookup.description')} {context.lookupFields.length === 0 ? ( - - No lookup fields found in the app. Please add a lookup field to use this plugin. - + {t('settings.lookup.errors.no-lookup-field-found')} ) : ( - Lookup Field - Source Attachment Field (in Related App) - Destination Attachment Field + + {t('settings.lookup.messages.lookup-field')} + + + {t('settings.lookup.messages.source-attachment-field')} + + + {t('settings.lookup.messages.destination-attachment-field')} + @@ -282,10 +287,10 @@ const Settings: React.FC = (props) => { - Cancel + {t('buttons.cancel')} - Save + {t('buttons.save')}
diff --git a/src/config/i18n.ts b/src/config/i18n.ts new file mode 100644 index 0000000..6d90c6b --- /dev/null +++ b/src/config/i18n.ts @@ -0,0 +1,27 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import kintoneLanguageDetector from '../common/kintoneLanguageDetector'; + +import enTranslation from './locales/en.json'; +import jaTranslation from './locales/ja.json'; + +i18n + .use(kintoneLanguageDetector) + .use(initReactI18next) + .init({ + fallbackLng: 'en', + // debug: true, + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + }, + resources: { + en: { + translation: enTranslation, + }, + ja: { + translation: jaTranslation, + }, + }, + }); + +export default i18n; diff --git a/src/config/index.tsx b/src/config/index.tsx index de63d1b..77e72e7 100644 --- a/src/config/index.tsx +++ b/src/config/index.tsx @@ -6,6 +6,8 @@ import ConfigApp from './ConfigApp'; import '../common/ui/51-modern-default.css'; +import './i18n'; + ((PLUGIN_ID) => { const root = document.getElementById('plugin-config-root'); invariant(root, 'The plugin configuration root element "plugin-config-root" is not found.'); diff --git a/src/config/locales/en.json b/src/config/locales/en.json new file mode 100644 index 0000000..3c8c64d --- /dev/null +++ b/src/config/locales/en.json @@ -0,0 +1,24 @@ +{ + "title": "Settings for the Kintone Lookup File Sync plugin", + "settings": { + "lookup": { + "title": "Field Mappings", + "description": "Select lookup and attachment fields that used for the file synchronization.", + "messages": { + "lookup-field": "Lookup Field", + "source-attachment-field": "Source Attachment Field (in Related App)", + "destination-attachment-field": "Destination Attachment Field" + }, + "errors": { + "no-lookup-field-found": "No lookup fields found in the app. Please add a lookup field to use this plugin.", + "incomplete-field-mapping-found": "Incomplete field mapping found", + "same-destination-attachment-field-found": "Same destination attachment fields found" + } + } + }, + "buttons": { + "save": "Save", + "cancel": "Cancel" + }, + "on-saved": "The plug-in settings have been saved. Please update the app!" +} diff --git a/src/config/locales/ja.json b/src/config/locales/ja.json new file mode 100644 index 0000000..c41b78d --- /dev/null +++ b/src/config/locales/ja.json @@ -0,0 +1,24 @@ +{ + "title": "Lookupファイル同期プラグイン設定", + "settings": { + "lookup": { + "title": "フィールドマッピング", + "description": "ルックアップフィールドでファイルを同期させる添付ファイルフィールドの対応付けを行います。", + "messages": { + "lookup-field": "ルックアップフィールド", + "source-attachment-field": "同期元の添付ファイルフィールド (関連アプリ)", + "destination-attachment-field": "同期先の添付ファイルフィールド" + }, + "errors": { + "no-lookup-field-found": "同期可能なルックアップフィールドが見つかりません。フォームの設定を見直してください。", + "incomplete-field-mapping-found": "設定の完了していないマッピングが見つかりました。", + "same-destination-attachment-field-found": "同期先の添付ファイルフィールドが重複しています。" + } + } + }, + "buttons": { + "save": "保存", + "cancel": "キャンセル" + }, + "on-saved": "設定を保存しました。アプリを更新してください。" +} diff --git a/src/desktop/index.tsx b/src/desktop/index.tsx index 621f13b..7b0e95b 100644 --- a/src/desktop/index.tsx +++ b/src/desktop/index.tsx @@ -42,7 +42,7 @@ type UpdateRecordAttachmentFieldValue = UpdateRecordAttachmentFieldValueItem[]; | kintone.events.MobileAppRecordCreateSubmitSuccessEvent | kintone.events.MobileAppRecordEditSubmitSuccessEvent, ) => { - const context = await getPluginContext(event.appId); + const context = await getPluginContext(event.appId, false); const mappings = filterConfigByPluginContext(loadPluginConfigLookup(PLUGIN_ID), context); if (mappings == null) { return event;