support language translation.
This commit is contained in:
198
package-lock.json
generated
198
package-lock.json
generated
@@ -9,16 +9,18 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kintone/rest-api-client": "^5.7.4",
|
"@kintone/rest-api-client": "^5.7.4",
|
||||||
"angular-expressions": "^1.4.3",
|
"angular-expressions": "^1.5.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"docxtemplater": "^3.65.1",
|
"docxtemplater": "^3.65.1",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
|
"i18next": "^25.3.0",
|
||||||
"moize": "^6.1.6",
|
"moize": "^6.1.6",
|
||||||
"pizzip": "^3.2.0",
|
"pizzip": "^3.2.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-error-boundary": "^6.0.0",
|
"react-error-boundary": "^6.0.0",
|
||||||
|
"react-i18next": "^15.6.0",
|
||||||
"tiny-invariant": "^1.3.3"
|
"tiny-invariant": "^1.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -26,8 +28,8 @@
|
|||||||
"@kintone/dts-gen": "^8.1.2",
|
"@kintone/dts-gen": "^8.1.2",
|
||||||
"@kintone/plugin-uploader": "^9.1.5",
|
"@kintone/plugin-uploader": "^9.1.5",
|
||||||
"@kintone/webpack-plugin-kintone-plugin": "^8.0.11",
|
"@kintone/webpack-plugin-kintone-plugin": "^8.0.11",
|
||||||
"@rspack/cli": "^1.4.2",
|
"@rspack/cli": "^1.4.3",
|
||||||
"@rspack/core": "^1.4.2",
|
"@rspack/core": "^1.4.3",
|
||||||
"@shin-chan/kypes": "^0.0.7",
|
"@shin-chan/kypes": "^0.0.7",
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/node": "^24.0.10",
|
"@types/node": "^24.0.10",
|
||||||
@@ -1152,28 +1154,28 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding": {
|
"node_modules/@rspack/binding": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.4.3.tgz",
|
||||||
"integrity": "sha512-NdTLlA20ufD0thFvDIwwPk+bX9yo3TDE4XjfvZYbwFyYvBgqJOWQflnbwLgvSTck0MSTiOqWIqpR88ymAvWTqg==",
|
"integrity": "sha512-bDKAruEbEdlozi8NkLrC0H+e/CfWuQgxi08akofLBp227Nd/n0yLF4VWaUkZr4lSbMJQBxXPattryDijDnoLwA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rspack/binding-darwin-arm64": "1.4.2",
|
"@rspack/binding-darwin-arm64": "1.4.3",
|
||||||
"@rspack/binding-darwin-x64": "1.4.2",
|
"@rspack/binding-darwin-x64": "1.4.3",
|
||||||
"@rspack/binding-linux-arm64-gnu": "1.4.2",
|
"@rspack/binding-linux-arm64-gnu": "1.4.3",
|
||||||
"@rspack/binding-linux-arm64-musl": "1.4.2",
|
"@rspack/binding-linux-arm64-musl": "1.4.3",
|
||||||
"@rspack/binding-linux-x64-gnu": "1.4.2",
|
"@rspack/binding-linux-x64-gnu": "1.4.3",
|
||||||
"@rspack/binding-linux-x64-musl": "1.4.2",
|
"@rspack/binding-linux-x64-musl": "1.4.3",
|
||||||
"@rspack/binding-wasm32-wasi": "1.4.2",
|
"@rspack/binding-wasm32-wasi": "1.4.3",
|
||||||
"@rspack/binding-win32-arm64-msvc": "1.4.2",
|
"@rspack/binding-win32-arm64-msvc": "1.4.3",
|
||||||
"@rspack/binding-win32-ia32-msvc": "1.4.2",
|
"@rspack/binding-win32-ia32-msvc": "1.4.3",
|
||||||
"@rspack/binding-win32-x64-msvc": "1.4.2"
|
"@rspack/binding-win32-x64-msvc": "1.4.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-darwin-arm64": {
|
"node_modules/@rspack/binding-darwin-arm64": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.4.3.tgz",
|
||||||
"integrity": "sha512-0fPOew7D0l/x6qFZYdyUqutbw15K98VLvES2/7x2LPssTgypE4rVmnQSmVBnge3Nr8Qs/9qASPRpMWXBaqMfOA==",
|
"integrity": "sha512-YwPYWvo+WhdQgb76ZnH6m4sXClcRJJ5UB3Qj7xABKDQNJ62MaczWHEPfh2LM4iSJ1IWMo9dW4yeEXa7U9aE94w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1185,9 +1187,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-darwin-x64": {
|
"node_modules/@rspack/binding-darwin-x64": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.4.3.tgz",
|
||||||
"integrity": "sha512-0Dh6ssGgwnd9G+IO8SwQaJ0RJ8NkQbk4hwoJH/u52Mnfl0EvhmNvuhkbSEoKn1U3kElOA2cxH/3gbYzuYExn3g==",
|
"integrity": "sha512-aynWl0uCfIVfzDiZtSA6l75U8zyIc0UBa0p/ZETHrIQlBHPKDmxVIOlpbJWprilw5i4a3nWbadKCzvb0Gb92iA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1199,9 +1201,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-linux-arm64-gnu": {
|
"node_modules/@rspack/binding-linux-arm64-gnu": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.4.3.tgz",
|
||||||
"integrity": "sha512-UHAzggS8Mc7b3Xguhj82HwujLqBZquCeo8qJj5XreNaMKGb6YRw/91dJOVmkNiLCB0bj71CRE1Cocd+Peq3N9A==",
|
"integrity": "sha512-x6OlSqt4esxj5hAZq+aPSG1pbNtjLPDw3cnQlfqv04kJO6MOwrH+j4DPc+/Q2qKdFzLw807eyvKd3O9leu+iPg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1213,9 +1215,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-linux-arm64-musl": {
|
"node_modules/@rspack/binding-linux-arm64-musl": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.4.3.tgz",
|
||||||
"integrity": "sha512-QybZ0VxlFih+upLoE7Le5cN3LpxJwk6EnEQTigmzpfc4c4SOC889ftBoIAO3IeBk+mF3H2C9xD+/NolTdwoeiw==",
|
"integrity": "sha512-6aCa76fW8WlSBc0bJKXLSql79NoFlua4b+59XN1kZln+yLstgicFiJSvAnw+9U7mrl7IP9UmVWTw3JBnHUtw4A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1227,9 +1229,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-linux-x64-gnu": {
|
"node_modules/@rspack/binding-linux-x64-gnu": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.4.3.tgz",
|
||||||
"integrity": "sha512-ucCCWdtH1tekZadrsYj6GNJ8EP21BM2uSE7MootbwLw8aBtgVTKUuRDQEps1h/rtrdthzd9XBX6Lc2N926gM+g==",
|
"integrity": "sha512-N2kUPPVjkky9KlK/a1QXvRivtTS0RJ1ZGRfkacycOTcKwB3nvrz6IqYOFhIst9Wjed677KELKP5zZv/VImfY7Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1241,9 +1243,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-linux-x64-musl": {
|
"node_modules/@rspack/binding-linux-x64-musl": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.4.3.tgz",
|
||||||
"integrity": "sha512-+Y2LS6Qyk2AZor8DqlA8yKCqElYr0Urjc3M66O4ZzlxDT5xXX0J2vp04AtFp0g81q/+UgV3cbC//dqDvO0SiBA==",
|
"integrity": "sha512-SAzoCLCHQMFoQ41i9APIfE2ndv3JT5LkPvl6V1FmiFRgZwH0jVKpIybulZtgLNgNh4nFIYES0+2XK8dZ28YR5g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1255,9 +1257,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-wasm32-wasi": {
|
"node_modules/@rspack/binding-wasm32-wasi": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.4.3.tgz",
|
||||||
"integrity": "sha512-3WvfHY7NvzORek3FcQWLI/B8wQ7NZe0e0Bub9GyLNVxe5Bi+dxnSzEg6E7VsjbUzKnYufJA0hDKbEJ2qCMvpdw==",
|
"integrity": "sha512-jrakte9rA3a+VfRqm4Qa3o+MI4lfYZGqQTdpWyC9GLi3USxyaU55hGYdd/TtGvDY82KvJfGTV8o+LRn0Pl77OA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"wasm32"
|
"wasm32"
|
||||||
],
|
],
|
||||||
@@ -1269,9 +1271,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-win32-arm64-msvc": {
|
"node_modules/@rspack/binding-win32-arm64-msvc": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.4.3.tgz",
|
||||||
"integrity": "sha512-Y6L9DrLFRW6qBBCY3xBt7townStN5mlcbBTuG1zeXl0KcORPv1G1Cq6HXP6f1em+YsHE1iwnNqLvv4svg5KsnQ==",
|
"integrity": "sha512-Tho05w0sUWKe7avQYYGwaL5xNDFRav4A4Su5DTCC6mQeokbndg0Lk7jtyYIp9ZHCStUOojR4PY/4zG918ky95w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1283,9 +1285,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-win32-ia32-msvc": {
|
"node_modules/@rspack/binding-win32-ia32-msvc": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.4.3.tgz",
|
||||||
"integrity": "sha512-FyTJrL7GcYXPWKUB9Oj2X29kfma6MUgM9PyXGy8gDMti21kMMhpHp/bGVqfurRbazDyklDuLLtbHuawpa6toeA==",
|
"integrity": "sha512-Hc8tC30FvW5h8r3wW7C0pqY5b5BlMk0Y7vi03Zt60r8WqmeNINvAsjzyifHikD4S4lyQQO4CGXZOzSBWUcYesw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -1297,9 +1299,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/binding-win32-x64-msvc": {
|
"node_modules/@rspack/binding-win32-x64-msvc": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.4.3.tgz",
|
||||||
"integrity": "sha512-ODSU26tmG8MfMFDHCaMLCORB64EVdEtDvPP5zJs0Mgh7vQaqweJtqgG0ukZCQy4ApUatOrMaZrLk557jp9Biyw==",
|
"integrity": "sha512-D+I6fl6Phq8+VElvf3sVTh+bqatk9Rjtgh4l2D7elIUkBguT5nAY3SX5wE/7iYnSdOBbP5mghU4exOG7NYqJYA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1311,9 +1313,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/cli": {
|
"node_modules/@rspack/cli": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/cli/-/cli-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/cli/-/cli-1.4.3.tgz",
|
||||||
"integrity": "sha512-S1d82mOdL0Iio/KoJ8E8HRAamBqpfvePZ+qkffs2sAYEzLrBQyI8dEADJ5SXPoHdyy8IafcrlRJnBh0ETLVVsg==",
|
"integrity": "sha512-6OLbIL5TxVsAiWjx7MZvA8hq7fz1m8rPDuvB9QhvpEFIpL3OqZf0+LTY60ApOFOSy+/vYWFe0oT+8NGOX65RjA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1334,14 +1336,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rspack/core": {
|
"node_modules/@rspack/core": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.4.3.tgz",
|
||||||
"integrity": "sha512-Mmk3X3fbOLtRq4jX8Ebp3rfjr75YgupvNksQb0WbaGEVr5l1b6woPH/LaXF2v9U9DP83wmpZJXJ8vclB5JfL/w==",
|
"integrity": "sha512-zWdAXleiYZ+SlappgDbjsoBWIQzyYJX5WwPXmoQnHJPb4K+zmjCL8MRfdIMIxXcg5IiQsBfiWY/lYhaZ2Jc0EA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@module-federation/runtime-tools": "0.15.0",
|
"@module-federation/runtime-tools": "0.15.0",
|
||||||
"@rspack/binding": "1.4.2",
|
"@rspack/binding": "1.4.3",
|
||||||
"@rspack/lite-tapable": "1.0.1"
|
"@rspack/lite-tapable": "1.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2576,9 +2578,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/angular-expressions": {
|
"node_modules/angular-expressions": {
|
||||||
"version": "1.4.3",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/angular-expressions/-/angular-expressions-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/angular-expressions/-/angular-expressions-1.5.0.tgz",
|
||||||
"integrity": "sha512-r7j+dqOuHy0OYiR5AazDixU/Us3TDN2FfuxGX4Dq6d61Y2MhBQHMdUNBfkkLPjDqVm2Is394h31gC3bcBwy9zw==",
|
"integrity": "sha512-ksiE8I2lg124ssP8BmJlQg5RgjyBl1SmZluQ2Sj89n6aHbbQhqRsPUGwW80uiHDhUVxhan0FBDemfei0rbWKlg==",
|
||||||
"license": "Unlicense"
|
"license": "Unlicense"
|
||||||
},
|
},
|
||||||
"node_modules/ansi-escapes": {
|
"node_modules/ansi-escapes": {
|
||||||
@@ -4679,14 +4681,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-n": {
|
"node_modules/eslint-plugin-n": {
|
||||||
"version": "17.20.0",
|
"version": "17.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.21.0.tgz",
|
||||||
"integrity": "sha512-IRSoatgB/NQJZG5EeTbv/iAx1byOGdbbyhQrNvWdCfTnmPxUT0ao9/eGOeG7ljD8wJBsxwE8f6tES5Db0FRKEw==",
|
"integrity": "sha512-1+iZ8We4ZlwVMtb/DcHG3y5/bZOdazIpa/4TySo22MLKdwrLcfrX0hbadnCvykSQCCmkAnWmIP8jZVb2AAq29A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.5.0",
|
"@eslint-community/eslint-utils": "^4.5.0",
|
||||||
"@typescript-eslint/utils": "^8.26.1",
|
|
||||||
"enhanced-resolve": "^5.17.1",
|
"enhanced-resolve": "^5.17.1",
|
||||||
"eslint-plugin-es-x": "^7.8.0",
|
"eslint-plugin-es-x": "^7.8.0",
|
||||||
"get-tsconfig": "^4.8.1",
|
"get-tsconfig": "^4.8.1",
|
||||||
@@ -5942,6 +5943,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/http-deceiver": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
|
||||||
@@ -6061,6 +6071,37 @@
|
|||||||
"node": ">=10.18"
|
"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": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
@@ -8586,6 +8627,32 @@
|
|||||||
"react": ">=16.13.1"
|
"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": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
@@ -10525,7 +10592,7 @@
|
|||||||
"version": "5.8.3",
|
"version": "5.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
@@ -10737,6 +10804,15 @@
|
|||||||
"node": ">= 0.8"
|
"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": {
|
"node_modules/watchpack": {
|
||||||
"version": "2.4.4",
|
"version": "2.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
|
||||||
|
@@ -15,16 +15,18 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kintone/rest-api-client": "^5.7.4",
|
"@kintone/rest-api-client": "^5.7.4",
|
||||||
"angular-expressions": "^1.4.3",
|
"angular-expressions": "^1.5.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"docxtemplater": "^3.65.1",
|
"docxtemplater": "^3.65.1",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
|
"i18next": "^25.3.0",
|
||||||
"moize": "^6.1.6",
|
"moize": "^6.1.6",
|
||||||
"pizzip": "^3.2.0",
|
"pizzip": "^3.2.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-error-boundary": "^6.0.0",
|
"react-error-boundary": "^6.0.0",
|
||||||
|
"react-i18next": "^15.6.0",
|
||||||
"tiny-invariant": "^1.3.3"
|
"tiny-invariant": "^1.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -32,8 +34,8 @@
|
|||||||
"@kintone/dts-gen": "^8.1.2",
|
"@kintone/dts-gen": "^8.1.2",
|
||||||
"@kintone/plugin-uploader": "^9.1.5",
|
"@kintone/plugin-uploader": "^9.1.5",
|
||||||
"@kintone/webpack-plugin-kintone-plugin": "^8.0.11",
|
"@kintone/webpack-plugin-kintone-plugin": "^8.0.11",
|
||||||
"@rspack/cli": "^1.4.2",
|
"@rspack/cli": "^1.4.3",
|
||||||
"@rspack/core": "^1.4.2",
|
"@rspack/core": "^1.4.3",
|
||||||
"@shin-chan/kypes": "^0.0.7",
|
"@shin-chan/kypes": "^0.0.7",
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/node": "^24.0.10",
|
"@types/node": "^24.0.10",
|
||||||
|
10
src/common/kintoneLanguageDetector.ts
Normal file
10
src/common/kintoneLanguageDetector.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { LanguageDetectorModule } from 'i18next';
|
||||||
|
|
||||||
|
const KintoneLanguageDetector: LanguageDetectorModule = {
|
||||||
|
type: 'languageDetector',
|
||||||
|
// init: () => {},
|
||||||
|
detect: () => kintone.getLoginUser().language,
|
||||||
|
// cacheUserLanguage: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default KintoneLanguageDetector;
|
@@ -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(', ')}`,
|
|
||||||
);
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
|
|
||||||
import { KintoneRestAPIClient } from '@kintone/rest-api-client';
|
import { KintoneRestAPIClient } from '@kintone/rest-api-client';
|
||||||
import moize from 'moize';
|
import moize from 'moize';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import invariant from 'tiny-invariant';
|
import invariant from 'tiny-invariant';
|
||||||
import { naturalCompare } from '../common/stringUtils';
|
import { naturalCompare } from '../common/stringUtils';
|
||||||
import { KintoneFormFieldProperties } from '../common/types';
|
import { KintoneFormFieldProperties } from '../common/types';
|
||||||
@@ -18,7 +19,7 @@ import styles from './Settings.module.css';
|
|||||||
|
|
||||||
const cachedFormFieldsProperties = moize.promise(async (appId: number): Promise<KintoneFormFieldProperties> => {
|
const cachedFormFieldsProperties = moize.promise(async (appId: number): Promise<KintoneFormFieldProperties> => {
|
||||||
const client = new KintoneRestAPIClient();
|
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: true });
|
||||||
return properties;
|
return properties;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ interface SettingsProps {
|
|||||||
|
|
||||||
const Settings: React.FC<SettingsProps> = (props) => {
|
const Settings: React.FC<SettingsProps> = (props) => {
|
||||||
const { pluginId } = props;
|
const { pluginId } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
const config = kintone.plugin.app.getConfig(pluginId);
|
const config = kintone.plugin.app.getConfig(pluginId);
|
||||||
const appId = kintone.app.getId();
|
const appId = kintone.app.getId();
|
||||||
invariant(appId, 'The app ID is not available. Please ensure you are on a Kintone app page.');
|
invariant(appId, 'The app ID is not available. Please ensure you are on a Kintone app page.');
|
||||||
@@ -36,7 +38,7 @@ const Settings: React.FC<SettingsProps> = (props) => {
|
|||||||
.filter((property) => property.type === 'FILE')
|
.filter((property) => property.type === 'FILE')
|
||||||
.sort((a, b) => naturalCompare(`${a.label} (${a.code})`, `${b.label} (${b.code})`));
|
.sort((a, b) => naturalCompare(`${a.label} (${a.code})`, `${b.label} (${b.code})`));
|
||||||
const options: KintonePluginSelectOptionData[] = [
|
const options: KintonePluginSelectOptionData[] = [
|
||||||
{ value: '', label: 'Select a File field', disabled: true }, // Default option
|
{ value: '', label: t('settings.template.messages.select-an-attachment-fields'), disabled: true }, // Default option
|
||||||
...fileFields.map((property) => ({
|
...fileFields.map((property) => ({
|
||||||
value: property.code,
|
value: property.code,
|
||||||
label: `${property.label} (${property.code})`,
|
label: `${property.label} (${property.code})`,
|
||||||
@@ -50,7 +52,7 @@ const Settings: React.FC<SettingsProps> = (props) => {
|
|||||||
const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
kintone.plugin.app.setConfig({ template }, () => {
|
kintone.plugin.app.setConfig({ template }, () => {
|
||||||
alert('The plug-in settings have been saved. Please update the app!');
|
alert(t('on-saved'));
|
||||||
window.location.href = `../../flow?app=${appId}`;
|
window.location.href = `../../flow?app=${appId}`;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -65,27 +67,26 @@ const Settings: React.FC<SettingsProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="settings">
|
<section className="settings">
|
||||||
<KintonePluginLabel>Settings for the Kintone Word output plugin</KintonePluginLabel>
|
<KintonePluginLabel>{t('title')}</KintonePluginLabel>
|
||||||
<form onSubmit={handleOnSubmit}>
|
<form onSubmit={handleOnSubmit}>
|
||||||
<KintonePluginRow>
|
<KintonePluginRow>
|
||||||
<KintonePluginTitle>
|
<KintonePluginTitle>
|
||||||
Template<KintonePluginRequire>*</KintonePluginRequire>
|
{t('settings.template.title')}
|
||||||
|
<KintonePluginRequire>*</KintonePluginRequire>
|
||||||
</KintonePluginTitle>
|
</KintonePluginTitle>
|
||||||
<KintonePluginDesc>Select a file field that contains the Word template file.</KintonePluginDesc>
|
<KintonePluginDesc> {t('settings.template.description')}</KintonePluginDesc>
|
||||||
{fileFields.length === 0 ? (
|
{fileFields.length === 0 ? (
|
||||||
<KintonePluginAlert>
|
<KintonePluginAlert>{t('settings.template.errors.no-attachment-field-found')}</KintonePluginAlert>
|
||||||
No file fields found in the app. Please add a file field to use this plugin.
|
|
||||||
</KintonePluginAlert>
|
|
||||||
) : (
|
) : (
|
||||||
<KintonePluginSelect value={template} onChange={handleOnChangeTemplate} options={options} />
|
<KintonePluginSelect value={template} onChange={handleOnChangeTemplate} options={options} />
|
||||||
)}
|
)}
|
||||||
</KintonePluginRow>
|
</KintonePluginRow>
|
||||||
<KintonePluginRow className={styles.buttons}>
|
<KintonePluginRow className={styles.buttons}>
|
||||||
<KintonePluginButton variant="dialog-cancel" type="button" onClick={handleOnClickCancel}>
|
<KintonePluginButton variant="dialog-cancel" type="button" onClick={handleOnClickCancel}>
|
||||||
Cancel
|
{t('buttons.cancel')}
|
||||||
</KintonePluginButton>
|
</KintonePluginButton>
|
||||||
<KintonePluginButton variant="dialog-ok" type="submit">
|
<KintonePluginButton variant="dialog-ok" type="submit">
|
||||||
Save
|
{t('buttons.save')}
|
||||||
</KintonePluginButton>
|
</KintonePluginButton>
|
||||||
</KintonePluginRow>
|
</KintonePluginRow>
|
||||||
</form>
|
</form>
|
||||||
|
27
src/config/i18n.ts
Normal file
27
src/config/i18n.ts
Normal file
@@ -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;
|
@@ -6,6 +6,8 @@ import ConfigApp from './ConfigApp';
|
|||||||
|
|
||||||
import '../common/ui/51-modern-default.css';
|
import '../common/ui/51-modern-default.css';
|
||||||
|
|
||||||
|
import './i18n';
|
||||||
|
|
||||||
((PLUGIN_ID) => {
|
((PLUGIN_ID) => {
|
||||||
const root = document.getElementById('plugin-config-root');
|
const root = document.getElementById('plugin-config-root');
|
||||||
invariant(root, 'The plugin configuration root element "plugin-config-root" is not found.');
|
invariant(root, 'The plugin configuration root element "plugin-config-root" is not found.');
|
||||||
|
20
src/config/locales/en.json
Normal file
20
src/config/locales/en.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"title": "Settings for the Kintone Word output plugin",
|
||||||
|
"settings": {
|
||||||
|
"template": {
|
||||||
|
"title": "Template",
|
||||||
|
"description": "Select a attachment field that contains the Word template file.",
|
||||||
|
"messages": {
|
||||||
|
"select-an-attachment-fields": "(Select an attachment field)"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"no-attachment-field-found": "No attachment fields found in the app. Please add an attachment field to use this plugin."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel"
|
||||||
|
},
|
||||||
|
"on-saved": "The plug-in settings have been saved. Please update the app!"
|
||||||
|
}
|
20
src/config/locales/ja.json
Normal file
20
src/config/locales/ja.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"title": "Word出力プラグイン設定",
|
||||||
|
"settings": {
|
||||||
|
"template": {
|
||||||
|
"title": "雛形ファイル",
|
||||||
|
"description": "Word雛形ファイルを保存する添付ファイルフィールドを選択してください。",
|
||||||
|
"messages": {
|
||||||
|
"select-an-attachment-fields": "(選択してください)"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"no-attachment-field-found": "このアプリに添付ファイルフィールドが見つかりません。フォームに添付ファイルフィールドを追加してください。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "キャンセル"
|
||||||
|
},
|
||||||
|
"on-saved": "設定を保存しました。アプリを更新してください。"
|
||||||
|
}
|
@@ -8,9 +8,9 @@ import expressionParser from 'docxtemplater/expressions';
|
|||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
import moize from 'moize';
|
import moize from 'moize';
|
||||||
import PizZip from 'pizzip';
|
import PizZip from 'pizzip';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import invariant from 'tiny-invariant';
|
import invariant from 'tiny-invariant';
|
||||||
import { DOCX_CONTENT_TYPE } from '../common/constants';
|
import { DOCX_CONTENT_TYPE } from '../common/constants';
|
||||||
import { LANGUAGE } from '../common/kintoneUtils';
|
|
||||||
import { KintoneFormFieldProperties } from '../common/types';
|
import { KintoneFormFieldProperties } from '../common/types';
|
||||||
import KintonePluginAlert from '../common/ui/KintonePluginAlert';
|
import KintonePluginAlert from '../common/ui/KintonePluginAlert';
|
||||||
import KintonePluginButton from '../common/ui/KintonePluginButton';
|
import KintonePluginButton from '../common/ui/KintonePluginButton';
|
||||||
@@ -26,7 +26,7 @@ interface MenuPanelProps {
|
|||||||
|
|
||||||
const cachedFormFieldsProperties = moize.promise(async (appId: number): Promise<KintoneFormFieldProperties> => {
|
const cachedFormFieldsProperties = moize.promise(async (appId: number): Promise<KintoneFormFieldProperties> => {
|
||||||
const client = new KintoneRestAPIClient();
|
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: false });
|
||||||
return properties;
|
return properties;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -72,7 +72,11 @@ const formatNumberRecordValue = (
|
|||||||
return formatValueWithUnit(formattedValue, property);
|
return formatValueWithUnit(formattedValue, property);
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatCalculatedRecordValue = (value: string, property: KintoneFormFieldProperty.Calc): string => {
|
const formatCalculatedRecordValue = (
|
||||||
|
value: string,
|
||||||
|
property: KintoneFormFieldProperty.Calc,
|
||||||
|
language: string,
|
||||||
|
): string => {
|
||||||
const { format } = property;
|
const { format } = property;
|
||||||
if (value === '') {
|
if (value === '') {
|
||||||
return '';
|
return '';
|
||||||
@@ -108,7 +112,7 @@ const formatCalculatedRecordValue = (value: string, property: KintoneFormFieldPr
|
|||||||
!isNaN(hours) && !isNaN(minutes),
|
!isNaN(hours) && !isNaN(minutes),
|
||||||
`Expected hours and minutes to be numbers, but got hours: ${hours}, minutes: ${minutes}`,
|
`Expected hours and minutes to be numbers, but got hours: ${hours}, minutes: ${minutes}`,
|
||||||
);
|
);
|
||||||
formattedValue = LANGUAGE === 'ja' ? `${hours}時間${minutes}分` : `${hours} hours ${minutes} minutes`;
|
formattedValue = language === 'ja' ? `${hours}時間${minutes}分` : `${hours} hours ${minutes} minutes`;
|
||||||
} else if (format === 'DAY_HOUR_MINUTE') {
|
} else if (format === 'DAY_HOUR_MINUTE') {
|
||||||
// "49:30" -> en: "2 days 1 hour 30 minutes", ja: "2日1時間30分
|
// "49:30" -> en: "2 days 1 hour 30 minutes", ja: "2日1時間30分
|
||||||
const [hours, minutes] = value.split(':').map((v) => Number(v));
|
const [hours, minutes] = value.split(':').map((v) => Number(v));
|
||||||
@@ -119,7 +123,7 @@ const formatCalculatedRecordValue = (value: string, property: KintoneFormFieldPr
|
|||||||
const days = Math.floor(Number(hours) / 24);
|
const days = Math.floor(Number(hours) / 24);
|
||||||
const remainingHours = Number(hours) % 24;
|
const remainingHours = Number(hours) % 24;
|
||||||
formattedValue =
|
formattedValue =
|
||||||
LANGUAGE === 'ja'
|
language === 'ja'
|
||||||
? `${days}日${remainingHours}時間${minutes}分`
|
? `${days}日${remainingHours}時間${minutes}分`
|
||||||
: `${days} days ${remainingHours} hours ${minutes} minutes`;
|
: `${days} days ${remainingHours} hours ${minutes} minutes`;
|
||||||
} else {
|
} else {
|
||||||
@@ -129,7 +133,11 @@ const formatCalculatedRecordValue = (value: string, property: KintoneFormFieldPr
|
|||||||
return formatValueWithUnit(formattedValue, property);
|
return formatValueWithUnit(formattedValue, property);
|
||||||
};
|
};
|
||||||
|
|
||||||
const record2data = (properties: KintoneFormFieldProperties, record: Partial<KintoneRecord>): TemplateData => {
|
const record2data = (
|
||||||
|
properties: KintoneFormFieldProperties,
|
||||||
|
record: Partial<KintoneRecord>,
|
||||||
|
language: string,
|
||||||
|
): TemplateData => {
|
||||||
const data: TemplateData = {};
|
const data: TemplateData = {};
|
||||||
for (const key in record) {
|
for (const key in record) {
|
||||||
if (Object.prototype.hasOwnProperty.call(record, key) && Object.prototype.hasOwnProperty.call(properties, key)) {
|
if (Object.prototype.hasOwnProperty.call(record, key) && Object.prototype.hasOwnProperty.call(properties, key)) {
|
||||||
@@ -149,7 +157,7 @@ const record2data = (properties: KintoneFormFieldProperties, record: Partial<Kin
|
|||||||
data[key] = formatNumberRecordValue(value, property);
|
data[key] = formatNumberRecordValue(value, property);
|
||||||
} else if (type === 'CALC') {
|
} else if (type === 'CALC') {
|
||||||
invariant(property.type === 'CALC', `Expected property type to be CALC, but got ${property.type}`);
|
invariant(property.type === 'CALC', `Expected property type to be CALC, but got ${property.type}`);
|
||||||
data[key] = formatCalculatedRecordValue(value, property);
|
data[key] = formatCalculatedRecordValue(value, property, language);
|
||||||
} else if (type === 'CHECK_BOX' || type === 'MULTI_SELECT' || type === 'CATEGORY') {
|
} else if (type === 'CHECK_BOX' || type === 'MULTI_SELECT' || type === 'CATEGORY') {
|
||||||
data[key] = value.map((v) => v);
|
data[key] = value.map((v) => v);
|
||||||
} else if (
|
} else if (
|
||||||
@@ -163,7 +171,7 @@ const record2data = (properties: KintoneFormFieldProperties, record: Partial<Kin
|
|||||||
});
|
});
|
||||||
} else if (type === 'SUBTABLE') {
|
} else if (type === 'SUBTABLE') {
|
||||||
invariant(property.type === 'SUBTABLE', `Expected property type to be SUBTABLE, but got ${property.type}`);
|
invariant(property.type === 'SUBTABLE', `Expected property type to be SUBTABLE, but got ${property.type}`);
|
||||||
data[key] = value.map((subRecord) => record2data(property.fields, subRecord.value));
|
data[key] = value.map((subRecord) => record2data(property.fields, subRecord.value, language));
|
||||||
} else if (type === 'FILE') {
|
} else if (type === 'FILE') {
|
||||||
invariant(property.type === 'FILE', `Expected property type to be FILE, but got ${property.type}`);
|
invariant(property.type === 'FILE', `Expected property type to be FILE, but got ${property.type}`);
|
||||||
data[key] = value.map((file) => ({
|
data[key] = value.map((file) => ({
|
||||||
@@ -184,31 +192,46 @@ const record2data = (properties: KintoneFormFieldProperties, record: Partial<Kin
|
|||||||
|
|
||||||
const MenuPanel: React.FC<MenuPanelProps> = (props) => {
|
const MenuPanel: React.FC<MenuPanelProps> = (props) => {
|
||||||
const { pluginId, event } = props;
|
const { pluginId, event } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
const appId = event.appId;
|
const appId = event.appId;
|
||||||
const properties = React.use(cachedFormFieldsProperties(appId));
|
const properties = React.use(cachedFormFieldsProperties(appId));
|
||||||
|
const language = kintone.getLoginUser().language;
|
||||||
const config = kintone.plugin.app.getConfig(pluginId);
|
const config = kintone.plugin.app.getConfig(pluginId);
|
||||||
const template: string = config.template ?? '';
|
const template: string = config.template ?? '';
|
||||||
|
|
||||||
if (template === '') {
|
if (template === '') {
|
||||||
return (
|
return (
|
||||||
<KintonePluginAlert>
|
<KintonePluginAlert>
|
||||||
Word output plugin: Template field is not set. Please configure the plugin.
|
{t('name')}: {t('errors.template-field-is-not-set')}
|
||||||
</KintonePluginAlert>
|
</KintonePluginAlert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const record = event.record[template];
|
const record = event.record[template];
|
||||||
if (record == null) {
|
if (record == null) {
|
||||||
return <KintonePluginAlert>Word output plugin: Template field is not available in this app.</KintonePluginAlert>;
|
return (
|
||||||
|
<KintonePluginAlert>
|
||||||
|
{t('name')}: {t('errors.template-field-is-not-available')}
|
||||||
|
</KintonePluginAlert>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (record.type !== 'FILE') {
|
if (record.type !== 'FILE') {
|
||||||
return <KintonePluginAlert>Word output plugin: Template field must be a file field.</KintonePluginAlert>;
|
return (
|
||||||
|
<KintonePluginAlert>
|
||||||
|
{t('name')}: {t('errors.template-field-must-be-an-attachment-field')}
|
||||||
|
</KintonePluginAlert>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (record.value.length === 0) {
|
if (record.value.length === 0) {
|
||||||
return <KintonePluginAlert>Word output plugin: Template field does not contain any files.</KintonePluginAlert>;
|
return (
|
||||||
|
<KintonePluginAlert>
|
||||||
|
{t('name')}: {t('errors.template-field-does-not-contain-any-files')}
|
||||||
|
</KintonePluginAlert>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (record.value.length > 1) {
|
if (record.value.length > 1) {
|
||||||
return (
|
return (
|
||||||
<KintonePluginAlert>
|
<KintonePluginAlert>
|
||||||
Word output plugin: Template field contains multiple files. Please ensure it contains only one file.
|
{t('name')}: {t('errors.template-field-contains-multiple-files')}
|
||||||
</KintonePluginAlert>
|
</KintonePluginAlert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -216,7 +239,7 @@ const MenuPanel: React.FC<MenuPanelProps> = (props) => {
|
|||||||
if (contentType !== DOCX_CONTENT_TYPE) {
|
if (contentType !== DOCX_CONTENT_TYPE) {
|
||||||
return (
|
return (
|
||||||
<KintonePluginAlert>
|
<KintonePluginAlert>
|
||||||
Word output plugin: The template file must be a DOCX file. The current file type is {contentType}.
|
{t('name')}: {t('errors.template-file-must-be-a-docx', { contentType })}
|
||||||
</KintonePluginAlert>
|
</KintonePluginAlert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -234,7 +257,7 @@ const MenuPanel: React.FC<MenuPanelProps> = (props) => {
|
|||||||
parser: expressionParser,
|
parser: expressionParser,
|
||||||
nullGetter: () => '',
|
nullGetter: () => '',
|
||||||
});
|
});
|
||||||
doc.render(record2data(properties, event.record));
|
doc.render(record2data(properties, event.record, language));
|
||||||
const out = doc.getZip().generate({ type: 'blob', mimeType: DOCX_CONTENT_TYPE });
|
const out = doc.getZip().generate({ type: 'blob', mimeType: DOCX_CONTENT_TYPE });
|
||||||
saveAs(out, 'output.docx');
|
saveAs(out, 'output.docx');
|
||||||
})
|
})
|
||||||
@@ -246,7 +269,7 @@ const MenuPanel: React.FC<MenuPanelProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<KintonePluginButton variant="normal" onClick={handleOnClickOutputButton}>
|
<KintonePluginButton variant="normal" onClick={handleOnClickOutputButton}>
|
||||||
Word出力
|
{t('buttons.output')}
|
||||||
</KintonePluginButton>
|
</KintonePluginButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
27
src/desktop/i18n.ts
Normal file
27
src/desktop/i18n.ts
Normal file
@@ -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;
|
@@ -6,6 +6,8 @@ import DesktopApp from './DesktopApp';
|
|||||||
|
|
||||||
import '../common/ui/51-modern-default.css';
|
import '../common/ui/51-modern-default.css';
|
||||||
|
|
||||||
|
import './i18n';
|
||||||
|
|
||||||
((PLUGIN_ID) => {
|
((PLUGIN_ID) => {
|
||||||
kintone.events.on(
|
kintone.events.on(
|
||||||
['app.record.detail.show', 'mobile.app.record.detail.show'],
|
['app.record.detail.show', 'mobile.app.record.detail.show'],
|
||||||
|
14
src/desktop/locales/en.json
Normal file
14
src/desktop/locales/en.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "Word output plugin",
|
||||||
|
"errors": {
|
||||||
|
"template-field-is-not-set": "Template field is not set. Please configure the plugin.",
|
||||||
|
"template-field-is-not-available": "Template field is not available in this app.",
|
||||||
|
"template-field-must-be-an-attachment-field": "Template field must be an attachment field.",
|
||||||
|
"template-field-does-not-contain-any-files": "Template field does not contain any files.",
|
||||||
|
"template-field-contains-multiple-files": "Template field contains multiple files. Please ensure it contains only one file.",
|
||||||
|
"template-file-must-be-a-docx": "The template file must be a Word (.docx) file. 'Mime-Type: {{contentType}}'."
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"output": "Output Word"
|
||||||
|
}
|
||||||
|
}
|
14
src/desktop/locales/ja.json
Normal file
14
src/desktop/locales/ja.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "Word出力プラグイン",
|
||||||
|
"errors": {
|
||||||
|
"template-field-is-not-set": "雛形ファイルが設定されていません。プラグインの設定を見直してください。",
|
||||||
|
"template-field-is-not-available": "雛形ファイルに設定された添付ファイルフィールドが見つかりませんでした。プラグインの設定を見直してください。",
|
||||||
|
"template-field-must-be-an-attachment-field": "雛形ファイルに設定されたフィールド型が添付ファイルフィールドではありません。プラグインの設定を見直してください。",
|
||||||
|
"template-field-does-not-contain-any-files": "雛形ファイルが添付されていません。",
|
||||||
|
"template-field-contains-multiple-files": "雛形ファイルとして複数登録されています。1つのみを指定してください。",
|
||||||
|
"template-file-must-be-a-docx": "雛形ファイルがWord形式(.docx)ではありません。'Mime-Type: {{contentType}}'"
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"output": "Word出力"
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user