From 71b1740d6670c44a17955c61c6bf780b35d27a7c Mon Sep 17 00:00:00 2001 From: Phillippe Caetano Date: Thu, 6 Nov 2025 23:12:15 -0300 Subject: [PATCH 1/9] feat: Initialize i18n --- package-lock.json | 782 ++++++++++++++++++++++++++++++- package.json | 1 + src/data/translations/pt-br.json | 2 + src/main.ts | 3 + src/util/i18n.ts | 18 + 5 files changed, 803 insertions(+), 3 deletions(-) create mode 100644 src/data/translations/pt-br.json create mode 100644 src/util/i18n.ts diff --git a/package-lock.json b/package-lock.json index f03f7c7d..53ddfd2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "standard-version": "^9.5.0", "svelte": "^4.2.19", "svelte-dnd-action": "^0.9.50", + "svelte-i18n": "^4.0.1", "svelte-loader": "^3.2.3", "svelte-multiselect": "^10.2.0", "svelte-preprocess": "^6.0.2", @@ -1138,6 +1139,62 @@ "dev": true, "license": "MIT" }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.6.tgz", + "integrity": "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/intl-localematcher": "0.6.2", + "decimal.js": "^10.4.3", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz", + "integrity": "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.4.tgz", + "integrity": "sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "@formatjs/icu-skeleton-parser": "1.8.16", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.16.tgz", + "integrity": "sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.2.tgz", + "integrity": "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@hutson/parse-repository-url": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", @@ -3424,6 +3481,23 @@ "dev": true, "license": "MIT" }, + "node_modules/cli-color": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz", + "integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.64", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -3982,6 +4056,20 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dev": true, + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/dargs": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", @@ -4057,6 +4145,13 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/dedent": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", @@ -4318,6 +4413,62 @@ "license": "MIT", "peer": true }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "dev": true, + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, "node_modules/esbuild": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", @@ -4897,6 +5048,22 @@ "node": ">=4.0" } }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -4946,6 +5113,17 @@ "@types/estree": "^1.0.0" } }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -5007,6 +5185,16 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, "node_modules/fast-copy": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", @@ -5437,6 +5625,13 @@ "node": ">=4" } }, + "node_modules/globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true, + "license": "MIT" + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -5458,6 +5653,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -5660,6 +5862,19 @@ "dev": true, "license": "MIT" }, + "node_modules/intl-messageformat": { + "version": "10.7.18", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.18.tgz", + "integrity": "sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/icu-messageformat-parser": "2.11.4", + "tslib": "^2.8.0" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -5769,6 +5984,13 @@ "node": ">=0.10.0" } }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-reference": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", @@ -8119,6 +8341,16 @@ "yallist": "^3.0.2" } }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es5-ext": "~0.10.2" + } + }, "node_modules/luxon": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.5.2.tgz", @@ -8185,6 +8417,26 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/memoizee": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", + "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "es5-ext": "^0.10.64", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/meow": { "version": "8.1.2", "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", @@ -8452,6 +8704,16 @@ "node": "*" } }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -8485,6 +8747,13 @@ "dev": true, "license": "MIT" }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true, + "license": "ISC" + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -9462,6 +9731,19 @@ "tslib": "^2.1.0" } }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -10581,6 +10863,468 @@ "svelte": ">=3.19.0" } }, + "node_modules/svelte-i18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svelte-i18n/-/svelte-i18n-4.0.1.tgz", + "integrity": "sha512-jaykGlGT5PUaaq04JWbJREvivlCnALtT+m87Kbm0fxyYHynkQaxQMnIKHLm2WeIuBRoljzwgyvz0Z6/CMwfdmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-color": "^2.0.3", + "deepmerge": "^4.2.2", + "esbuild": "^0.19.2", + "estree-walker": "^2", + "intl-messageformat": "^10.5.3", + "sade": "^1.8.1", + "tiny-glob": "^0.2.9" + }, + "bin": { + "svelte-i18n": "dist/cli.js" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "svelte": "^3 || ^4 || ^5" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/svelte-i18n/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/svelte-i18n/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/svelte-loader": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/svelte-loader/-/svelte-loader-3.2.3.tgz", @@ -10810,6 +11554,31 @@ "readable-stream": "3" } }, + "node_modules/timers-ext": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", + "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", + "dev": true, + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, "node_modules/title-case": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/title-case/-/title-case-4.3.1.tgz", @@ -10875,9 +11644,9 @@ "license": "Apache-2.0" }, "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -11018,6 +11787,13 @@ "webidl-conversions": "^4.0.2" } }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "dev": true, + "license": "ISC" + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", diff --git a/package.json b/package.json index 946ddcfa..f8b69f1d 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "standard-version": "^9.5.0", "svelte": "^4.2.19", "svelte-dnd-action": "^0.9.50", + "svelte-i18n": "^4.0.1", "svelte-loader": "^3.2.3", "svelte-multiselect": "^10.2.0", "svelte-preprocess": "^6.0.2", diff --git a/src/data/translations/pt-br.json b/src/data/translations/pt-br.json new file mode 100644 index 00000000..2c63c085 --- /dev/null +++ b/src/data/translations/pt-br.json @@ -0,0 +1,2 @@ +{ +} diff --git a/src/main.ts b/src/main.ts index 33d2e664..b9c75701 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,6 +10,7 @@ import { import domtoimage from "dom-to-image"; import StatBlockRenderer from "./view/statblock"; +import { initI18n } from "./util/i18n"; import { nanoid } from "./util/util"; import type { Monster, StatblockParameters } from "../index"; import StatblockSettingTab from "./settings/settings"; @@ -135,6 +136,8 @@ export default class StatBlockPlugin extends Plugin { await this.loadSettings(); await this.saveSettings(); + initI18n(); + this.manager.initialize(this.settings); this.register(() => this.manager.unload()); diff --git a/src/util/i18n.ts b/src/util/i18n.ts new file mode 100644 index 00000000..3cc92302 --- /dev/null +++ b/src/util/i18n.ts @@ -0,0 +1,18 @@ +import { register, init, getLocaleFromNavigator } from "svelte-i18n"; + +export function initI18n() { + const lang = moment.locale(); + + //register("en", () => import("./../data/translations/en.json")); + register("pt-br", () => import("./../data/translations/pt-br.json")); + + init({ + fallbackLocale: lang, + initialLocale: getLocaleFromNavigator(), + handleMissingMessage: ({ locale, id, defaultValue }) => { + if ("en" === lang) return; + console.log(`Missing translation: "${id}"`); + return defaultValue; + } + }); +} From 9a0cbe26d4b6e2359f89a26007bd9d5b78638033 Mon Sep 17 00:00:00 2001 From: Phillippe Caetano Date: Thu, 6 Nov 2025 23:18:48 -0300 Subject: [PATCH 2/9] feat: Translate plugin Settings screen --- src/data/translations/pt-br.json | 107 +++++++++++++++++ src/settings/settings.ts | 198 ++++++++++++++++--------------- 2 files changed, 208 insertions(+), 97 deletions(-) diff --git a/src/data/translations/pt-br.json b/src/data/translations/pt-br.json index 2c63c085..0be6d64f 100644 --- a/src/data/translations/pt-br.json +++ b/src/data/translations/pt-br.json @@ -1,2 +1,109 @@ { + "Actions": "Ações", + "Add Creature": "Adicionar Criatura", + "Add Dice Roller dice to statblocks by default. Use ": "Adicione dados do Dice Roller aos blocos de estatísticas por padrão. Use ", + "Add New Layout": "Adicionar Novo Layout", + "Advanced Settings": "Configurações Avançadas", + " and all objects must have the ": "e todos os objetos devem ter a propriedade", + "Are you sure?": "Tem certeza?", + "Are you sure you want to import this layout?": "Tem certeza de que deseja importar este layout?", + "Armor Class": "Classe de Armadura", + "as-is": "como são", + "Automatically Parse Frontmatter for Creatures": "Analisar Automaticamente Frontmatter para Criaturas", + "Bestiary": "Bestiário", + "Bestiary Folder": "Pasta do Bestiário", + "Bonus Actions": "Ações Bônus", + "Cancel": "Cancelar", + "Cha": "Car", + "Charisma": "Carisma", + "Challenge": "Nível de Desafio", + "Change the default statblock layout used, if not specified.": "Altere o layout padrão usado no bloco de estatística, se não especificado.", + "Choose File(s)": "Escolher Arquivo(s)", + "Con": "Con", + "Constitution": "Constituição", + "Condition Immunities": "Imunidade a Condição", + "Copy YAML": "Copiar YAML", + "Create Copy": "Criar Cópia", + "Create Layout": "Criar Layout", + "Creature YAML copied to clipboard": "YAML da criatura copiado para a área de transferência", + "Damage Immunities": "Imunidade a Dano", + "Damage Resistances": "Resistência a Dano", + "Damage Vulnerabilities": "Vulnerabilidade a Dano", + "Debug messages will be displayed by the file parser.": "Mensagens de depuração serão exibidas pelo analisador de arquivos.", + "Default Layout": "Layout Padrão", + "Delete": "Excluir", + "Dex": "Des", + "Dexterity": "Destreza", + "Edit": "Editar", + "Enable Debug Messages": "Habilitar Mensagens de Depuração", + "Enable 5e SRD": "Habilitar SRD 5e", + "Export as JSON": "Exportar como JSON", + "Export as PNG": "Exportar como PNG", + "Fantasy Statblocks Settings": "Configurações de Fantasy Statblocks", + "General Settings": "Configuração Geral", + "Hit Points": "Pontos de Vida", + "Import": "Importar", + "Import 5e.tools Data": "Importar Dados do 5e.tools", + "Import a custom layout from a JSON file.": "Importar um layout personalizado de um arquivo JSON.", + "Import a PC or NPC exported from Pathbuilder2e.": "Importar um PC ou NPC exportado do Pathbuilder2e.", + "Import and don't ask again": "Importar e não perguntar novamente", + "Import creatures from creature files. Monsters are stored by name, so only the last creature by that name will be saved. This is destructive - any saved creature will be overwritten.": "Importar criaturas de arquivos de criaturas. Os monstros são armazenados por nome, portanto, apenas a última criatura com esse nome será salva. Isso é destrutivo - qualquer criatura salva será sobrescrita.", + "Import CritterDB Data": "Importar Dados do CritterDB", + "Import DnDAppFile": "Importar DnDAppFile", + "Import DnDAppFile Data": "Importar Dados do DnDAppFile", + "Import From JSON": "Importar de JSON", + "Import Generic Data": "Importar Dados Genéricos", + "Import generic JSON files. JSON objects will be imported ": "Importar arquivos JSON genéricos. Os objetos JSON serão importados", + "Import Homebrew Creatures": "Importar Criaturas Homebrew", + "Import Improved Initiative Data": "Importar Dados do Improved Initiative", + "Import Pathbuilder Data": "Importar Dados do 5e.tools", + "Import PF2eMonsterTools Data": "Importar Dados do PF2eMonsterTools", + "Import TetraCube Data": "Importar Dados do TetraCube", + "Int": "Int", + "Intelligence": "Inteligência", + "Integrate Dice Roller": "Integrar Dice Roller", + "Invalid layout imported": "Layout inválido importado", + "Invalid layout imported: layout does not have a name": "Layout inválido importado: o layout não possui um nome", + "Invalid layout imported: no blocks defined in layout.": "Layout inválido importado: nenhum bloco definido no layout.", + "Invalid monster": "Monstro inválido", + "Languages": "Idiomas", + "Layout": "Layout", + "Layouts": "Layouts", + "Legendary Actions": "Ações Lendárias", + "New statblock layouts can be created and managed here. A specific layout can be used for a creature using the ": "Novos layouts de blocos de estatísticas podem ser criados e gerenciados aqui. Um layout específico pode ser usado para uma criatura usando o parâmetro", + "Note Parsing": "Análise de Notas", + "Only import content that you own.": "Importe apenas conteúdo que você possui.", + " parameter.": ".", + "Please note: these links will not be added to the graph.": "Observação: esses links não serão adicionados ao gráfico.", + "Proficiency Bonus": "Bônus de Proficiência", + " property.": ".", + "Reactions": "Reações", + "Render Dice Rolls": "Renderizar Rolagens de Dados", + "Restore Default Layouts": "Restaurar Layouts Padrão", + "Roll graphical dice inside statblocks by default. Use ": "Role dados gráficos dentro dos blocos de estatísticas por padrão. Use ", + "Save to Bestiary": "Salvar no Bestiário", + "Saves": "Salvaguardas", + "Senses": "Sentidos", + "Show Advanced Options": "Exibir Opções Avançadas", + "Show advanced options when editing layout blocks.": "Exibir opções avançadas ao editar blocos de layout.", + "Skills": "Perícias", + "Speed": "Deslocamento", + "Str": "For", + "Strength": "Força", + "The \"Parse Frontmatter for Creatures\" command can also be used.": "O comando \"Parse Frontmatter for Creatures\" também pode ser usado.", + "The plugin will attempt to detect wikilinks inside Statblocks.": "O plugin tentará detectar wikilinks dentro dos blocos de estatísticas.", + "The plugin will only parse notes inside these folders and their children.": "O plugin analisará apenas as notas dentro dessas pastas e suas subpastas.", + "The plugin will watch the vault for creatures defined in note frontmatter.": "O plugin monitorará o cofre em busca de criaturas definidas nas notas frontmatter.", + "There was an error displaying the settings tab for 5e Statblocks.": "Ocorreu um erro ao exibir a aba de configurações para Statblocks 5e.", + "This can cause issues sometimes when using sync services.": "Isso pode causar problemas ao usar serviços de sincronização.", + "This Layout includes JavaScript blocks. JavaScript blocks can execute code in your vault, which could cause loss or corruption of data.": "Este Layout inclui blocos JavaScript. Blocos JavaScript podem executar código em seu cofre, o que pode causar perda ou corrupção de dados.", + "This setting is only usable with the Dice Roller plugin enabled.": "Esta configuração só pode ser usada com o plugin Dice Roller ativado.", + "This setting is currently disabled.": "Essa configuração está desativada no momento.", + "This will cause to plugin to save data to a temporary file before saving the actual data file in an attempt to prevent data loss.": "Isso fará com que o plugin salve os dados em um arquivo temporário antes de salvar o arquivo de dados real, numa tentativa de evitar a perda de dados.", + " to disable per-statblock.": " para desativar no bloco de estatística.", + "Try to Render Wikilinks": "Tentar Renderizar Wikilinks.", + "Try to Save Data Atomically": "Tentar Salvar Dados Atomicamente", + "Use the Dungeons & Dragons 5th Edition System Reference Document monsters.": "Use os monstros do Documento de Referência do Sistema do Dungeons & Dragons 5ª Edição.", + "Wis": "Sab", + "Wisdom": "Sabedoria" } diff --git a/src/settings/settings.ts b/src/settings/settings.ts index bf91b286..1fe576d2 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -8,6 +8,8 @@ import { Setting, TFolder } from "obsidian"; +import { _ } from "svelte-i18n"; +import { get } from "svelte/store"; import type StatBlockPlugin from "src/main"; import LayoutEditor from "./layout/LayoutEditor.svelte"; @@ -28,6 +30,8 @@ import { Watcher } from "src/watcher/watcher"; import Creatures from "./creatures/Creatures.svelte"; import { EditMonsterModal } from "./modal"; +const t = get(_); + export default class StatblockSettingTab extends PluginSettingTab { importer: Importer; results: Partial[] = []; @@ -46,7 +50,7 @@ export default class StatblockSettingTab extends PluginSettingTab { containerEl.addClass("statblock-settings"); - containerEl.createEl("h2", { text: "Fantasy Statblocks Settings" }); + containerEl.createEl("h2", { text: t("Fantasy Statblocks Settings") }); this.generateTopSettings(containerEl.createDiv()); this.generateParseSettings(containerEl.createDiv()); @@ -69,24 +73,24 @@ export default class StatblockSettingTab extends PluginSettingTab { } catch (e) { console.error(e); new Notice( - "There was an error displaying the settings tab for 5e Statblocks." + t("There was an error displaying the settings tab for 5e Statblocks.") ); } } generateAdvancedSettings(container: HTMLDivElement) { container.empty(); - new Setting(container).setHeading().setName("Advanced Settings"); + new Setting(container).setHeading().setName(t("Advanced Settings")); new Setting(container) - .setName("Try to Save Data Atomically") + .setName(t("Try to Save Data Atomically")) .setDesc( createFragment((e) => { e.createSpan({ - text: "This will cause to plugin to save data to a temporary file before saving the actual data file in an attempt to prevent data loss." + text: t("This will cause to plugin to save data to a temporary file before saving the actual data file in an attempt to prevent data loss.") }); e.createEl("br"); e.createSpan({ - text: "This can cause issues sometimes when using sync services." + text: t("This can cause issues sometimes when using sync services.") }); e.createEl("br"); const warning = e.createDiv(); @@ -95,7 +99,7 @@ export default class StatblockSettingTab extends PluginSettingTab { attr: { style: "color: var(--text-error)" }, - text: "This setting is currently disabled." + text: t("This setting is currently disabled.") }); }) ) @@ -111,7 +115,7 @@ export default class StatblockSettingTab extends PluginSettingTab { generateTopSettings(container: HTMLDivElement) { container.empty(); - new Setting(container).setHeading().setName("General Settings"); + new Setting(container).setHeading().setName(t("General Settings")); /* new Setting(container) .setName("Enable Export to PNG") .setDesc( @@ -133,20 +137,20 @@ export default class StatblockSettingTab extends PluginSettingTab { }) ); */ new Setting(container) - .setName("Integrate Dice Roller") + .setName(t("Integrate Dice Roller")) .setDesc( createFragment((e) => { if (this.plugin.diceRollerInstalled) { e.createSpan({ - text: "Add Dice Roller dice to statblocks by default. Use " + text: t("Add Dice Roller dice to statblocks by default. Use ") }); e.createEl("code", { text: "dice: false" }); e.createSpan({ - text: " to disable per-statblock." + text: t(" to disable per-statblock.") }); } else { e.createSpan({ - text: "This setting is only usable with the Dice Roller plugin enabled." + text: t("This setting is only usable with the Dice Roller plugin enabled.") }); } }) @@ -159,20 +163,20 @@ export default class StatblockSettingTab extends PluginSettingTab { }) ); new Setting(container) - .setName("Render Dice Rolls") + .setName(t("Render Dice Rolls")) .setDesc( createFragment((e) => { if (this.plugin.diceRollerInstalled) { e.createSpan({ - text: "Roll graphical dice inside statblocks by default. Use " + text: t("Roll graphical dice inside statblocks by default. Use ") }); e.createEl("code", { text: "render: false" }); e.createSpan({ - text: " to disable per-statblock." + text: t(" to disable per-statblock.") }); } else { e.createSpan({ - text: "This setting is only usable with the Dice Roller plugin enabled." + text: t("This setting is only usable with the Dice Roller plugin enabled.") }); } }) @@ -200,15 +204,15 @@ export default class StatblockSettingTab extends PluginSettingTab { }) ); new Setting(container) - .setName("Try to Render Wikilinks") + .setName(t("Try to Render Wikilinks")) .setDesc( createFragment((e) => { e.createSpan({ - text: "The plugin will attempt to detect wikilinks inside Statblocks." + text: t("The plugin will attempt to detect wikilinks inside Statblocks.") }); e.createEl("br"); e.createEl("strong", { - text: "Please note: these links will not be added to the graph." + text: t("Please note: these links will not be added to the graph.") }); }) ) @@ -221,11 +225,11 @@ export default class StatblockSettingTab extends PluginSettingTab { }) ); new Setting(container) - .setName("Enable 5e SRD") + .setName(t("Enable 5e SRD")) .setDesc( createFragment((e) => { e.createSpan({ - text: "Use the Dungeons & Dragons 5th Edition System Reference Document monsters." + text: t("Use the Dungeons & Dragons 5th Edition System Reference Document monsters.") }); }) ) @@ -247,18 +251,18 @@ export default class StatblockSettingTab extends PluginSettingTab { const additionalContainer = containerEl.createDiv( "statblock-additional-container" ); - new Setting(additionalContainer).setHeading().setName("Note Parsing"); + new Setting(additionalContainer).setHeading().setName(t("Note Parsing")); new Setting(additionalContainer) - .setName("Automatically Parse Frontmatter for Creatures") + .setName(t("Automatically Parse Frontmatter for Creatures")) .setDesc( createFragment((e) => { e.createSpan({ - text: "The plugin will watch the vault for creatures defined in note frontmatter." + text: t("The plugin will watch the vault for creatures defined in note frontmatter.") }); e.createEl("br"); e.createEl("br"); e.createSpan({ - text: `The "Parse Frontmatter for Creatures" command can also be used.` + text: t(`The \"Parse Frontmatter for Creatures\" command can also be used.`) }); }) ) @@ -274,11 +278,11 @@ export default class StatblockSettingTab extends PluginSettingTab { ); }); new Setting(additionalContainer) - .setName("Enable Debug Messages") + .setName(t("Enable Debug Messages")) .setDesc( createFragment((e) => { e.createSpan({ - text: "Debug messages will be displayed by the file parser." + text: t("Debug messages will be displayed by the file parser.") }); }) ) @@ -291,9 +295,9 @@ export default class StatblockSettingTab extends PluginSettingTab { ); let path: string; new Setting(additionalContainer) - .setName("Bestiary Folder") + .setName(t("Bestiary Folder")) .setDesc( - "The plugin will only parse notes inside these folders and their children." + t("The plugin will only parse notes inside these folders and their children.") ) .addText(async (text) => { let folders = this.app.vault @@ -347,7 +351,7 @@ export default class StatblockSettingTab extends PluginSettingTab { } generateLayouts(containerEl: HTMLDivElement) { containerEl.empty(); - new Setting(containerEl).setHeading().setName("Layouts"); + new Setting(containerEl).setHeading().setName(t("Layouts")); const statblockCreatorContainer = containerEl.createDiv( "statblock-additional-container" @@ -358,15 +362,15 @@ export default class StatblockSettingTab extends PluginSettingTab { .appendChild( createFragment((el) => { el.createSpan({ - text: "New statblock layouts can be created and managed here. A specific layout can be used for a creature using the " + text: t("New statblock layouts can be created and managed here. A specific layout can be used for a creature using the ") }); el.createEl("code", { text: "layout" }); - el.createSpan({ text: " parameter." }); + el.createSpan({ text: t(" parameter.") }); }) ); const importFile = new Setting(statblockCreatorContainer) - .setName("Import From JSON") - .setDesc("Import a custom layout from a JSON file."); + .setName(t("Import From JSON")) + .setDesc(t("Import a custom layout from a JSON file.")); const inputFile = createEl("input", { attr: { type: "file", @@ -392,14 +396,14 @@ export default class StatblockSettingTab extends PluginSettingTab { ); if (!layout) { reject( - new Error("Invalid layout imported") + new Error(t("Invalid layout imported")) ); return; } if (!layout?.name) { reject( new Error( - "Invalid layout imported: layout does not have a name" + t("Invalid layout imported: layout does not have a name") ) ); return; @@ -408,7 +412,7 @@ export default class StatblockSettingTab extends PluginSettingTab { if (!layout?.blocks) { reject( new Error( - "Invalid layout imported: no blocks defined in layout." + t("Invalid layout imported: no blocks defined in layout.") ) ); return; @@ -457,11 +461,11 @@ export default class StatblockSettingTab extends PluginSettingTab { b.onClick(() => inputFile.click()); }); new Setting(statblockCreatorContainer) - .setName("Add New Layout") + .setName(t("Add New Layout")) .addButton((b) => b .setIcon("plus-with-circle") - .setTooltip("Add New Layout") + .setTooltip(t("Add New Layout")) .onClick(() => { const modal = new CreateStatblockModal(this.plugin); modal.onClose = async () => { @@ -482,9 +486,9 @@ export default class StatblockSettingTab extends PluginSettingTab { const statblockAdditional = statblockCreatorContainer.createDiv("additional"); new Setting(statblockAdditional) - .setName("Default Layout") + .setName(t("Default Layout")) .setDesc( - "Change the default statblock layout used, if not specified." + t("Change the default statblock layout used, if not specified.") ) .addDropdown(async (d) => { for (const layout of this.plugin.manager.getAllLayouts()) { @@ -510,8 +514,8 @@ export default class StatblockSettingTab extends PluginSettingTab { }); }); new Setting(statblockAdditional) - .setName("Show Advanced Options") - .setDesc("Show advanced options when editing layout blocks.") + .setName(t("Show Advanced Options")) + .setDesc(t("Show advanced options when editing layout blocks.")) .addToggle((t) => t .setValue(this.plugin.settings.showAdvanced) @@ -559,7 +563,7 @@ export default class StatblockSettingTab extends PluginSettingTab { if (this.plugin.manager.getAllDefaultLayouts().some((f) => f.removed)) { new Setting(layoutContainer) - .setName("Restore Default Layouts") + .setName(t("Restore Default Layouts")) .addButton((b) => { b.setIcon("rotate-ccw").onClick(async () => { for (const layout of Object.values( @@ -584,7 +588,7 @@ export default class StatblockSettingTab extends PluginSettingTab { .setName(layout.name) .addExtraButton((b) => { b.setIcon("pencil") - .setTooltip("Edit") + .setTooltip(t("Edit")) .onClick(() => { const modal = new CreateStatblockModal( this.plugin, @@ -627,7 +631,7 @@ export default class StatblockSettingTab extends PluginSettingTab { setting .addExtraButton((b) => { b.setIcon("duplicate-glyph") - .setTooltip("Create Copy") + .setTooltip(t("Create Copy")) .onClick(async () => { const dupe = this.getDuplicate(layout); this.plugin.settings.layouts.push(dupe); @@ -642,7 +646,7 @@ export default class StatblockSettingTab extends PluginSettingTab { }) .addExtraButton((b) => { b.setIcon("import-glyph") - .setTooltip("Export as JSON") + .setTooltip(t("Export as JSON")) .onClick(() => { const link = createEl("a"); const file = new Blob([JSON.stringify(layout)], { @@ -657,7 +661,7 @@ export default class StatblockSettingTab extends PluginSettingTab { }) .addExtraButton((b) => { b.setIcon("trash") - .setTooltip("Delete") + .setTooltip(t("Delete")) .onClick(async () => { layout.removed = true; this.plugin.settings.defaultLayouts[layout.id] = @@ -672,7 +676,7 @@ export default class StatblockSettingTab extends PluginSettingTab { .setName(layout.name) .addExtraButton((b) => { b.setIcon("pencil") - .setTooltip("Edit") + .setTooltip(t("Edit")) .onClick(() => { const modal = new CreateStatblockModal( this.plugin, @@ -708,7 +712,7 @@ export default class StatblockSettingTab extends PluginSettingTab { }) .addExtraButton((b) => { b.setIcon("duplicate-glyph") - .setTooltip("Create Copy") + .setTooltip(t("Create Copy")) .onClick(async () => { const dupe = this.getDuplicate(layout); this.plugin.settings.layouts.push(dupe); @@ -722,7 +726,7 @@ export default class StatblockSettingTab extends PluginSettingTab { }) .addExtraButton((b) => { b.setIcon("import-glyph") - .setTooltip("Export as JSON") + .setTooltip(t("Export as JSON")) .onClick(() => { const link = createEl("a"); const file = new Blob([JSON.stringify(layout)], { @@ -737,7 +741,7 @@ export default class StatblockSettingTab extends PluginSettingTab { }) .addExtraButton((b) => { b.setIcon("trash") - .setTooltip("Delete") + .setTooltip(t("Delete")) .onClick(async () => { this.plugin.settings.layouts = this.plugin.settings.layouts.filter( @@ -756,20 +760,20 @@ export default class StatblockSettingTab extends PluginSettingTab { containerEl.empty(); new Setting(containerEl) .setHeading() - .setName("Import Homebrew Creatures"); + .setName(t("Import Homebrew Creatures")); const importSettingsContainer = containerEl.createDiv( "statblock-additional-container" ); new Setting(importSettingsContainer).setDesc( - "Import creatures from creature files. Monsters are stored by name, so only the last creature by that name will be saved. This is destructive - any saved creature will be overwritten." + t("Import creatures from creature files. Monsters are stored by name, so only the last creature by that name will be saved. This is destructive - any saved creature will be overwritten.") ); const importAdditional = importSettingsContainer.createDiv("additional"); const importAppFile = new Setting(importAdditional) - .setName("Import DnDAppFile") - .setDesc("Only import content that you own."); + .setName(t("Import DnDAppFile")) + .setDesc(t("Only import content that you own.")); const inputAppFile = createEl("input", { attr: { type: "file", @@ -794,8 +798,8 @@ export default class StatblockSettingTab extends PluginSettingTab { }; importAppFile.addButton((b) => { - b.setButtonText("Choose File(s)").setTooltip( - "Import DnDAppFile Data" + b.setButtonText(t("Choose File(s)")).setTooltip( + t("Import DnDAppFile Data") ); b.buttonEl.addClass("statblock-file-upload"); b.buttonEl.appendChild(inputAppFile); @@ -803,8 +807,8 @@ export default class StatblockSettingTab extends PluginSettingTab { }); const importImprovedInitiative = new Setting(importAdditional) - .setName("Import Improved Initiative Data") - .setDesc("Only import content that you own."); + .setName(t("Import Improved Initiative Data")) + .setDesc(t("Only import content that you own.")); const inputImprovedInitiative = createEl("input", { attr: { type: "file", @@ -829,8 +833,8 @@ export default class StatblockSettingTab extends PluginSettingTab { }; importImprovedInitiative.addButton((b) => { - b.setButtonText("Choose File(s)").setTooltip( - "Import Improved Initiative Data" + b.setButtonText(t("Choose File(s)")).setTooltip( + t("Import Improved Initiative Data") ); b.buttonEl.addClass("statblock-file-upload"); b.buttonEl.appendChild(inputImprovedInitiative); @@ -838,8 +842,8 @@ export default class StatblockSettingTab extends PluginSettingTab { }); const importCritterDB = new Setting(importAdditional) - .setName("Import CritterDB Data") - .setDesc("Only import content that you own."); + .setName(t("Import CritterDB Data")) + .setDesc(t("Only import content that you own.")); const inputCritterDB = createEl("input", { attr: { type: "file", @@ -864,8 +868,8 @@ export default class StatblockSettingTab extends PluginSettingTab { }; importCritterDB.addButton((b) => { - b.setButtonText("Choose File(s)").setTooltip( - "Import CritterDB Data" + b.setButtonText(t("Choose File(s)")).setTooltip( + t("Import CritterDB Data") ); b.buttonEl.addClass("statblock-file-upload"); b.buttonEl.appendChild(inputCritterDB); @@ -873,8 +877,8 @@ export default class StatblockSettingTab extends PluginSettingTab { }); const import5eTools = new Setting(importAdditional) - .setName("Import 5e.tools Data") - .setDesc("Only import content that you own."); + .setName(t("Import 5e.tools Data")) + .setDesc(t("Only import content that you own.")); const input5eTools = createEl("input", { attr: { type: "file", @@ -895,16 +899,16 @@ export default class StatblockSettingTab extends PluginSettingTab { }; import5eTools.addButton((b) => { - b.setButtonText("Choose File(s)").setTooltip( - "Import 5e.tools Data" + b.setButtonText(t("Choose File(s)")).setTooltip( + t("Import 5e.tools Data") ); b.buttonEl.addClass("statblock-file-upload"); b.buttonEl.appendChild(input5eTools); b.onClick(() => input5eTools.click()); }); const importTetra = new Setting(importAdditional) - .setName("Import TetraCube Data") - .setDesc("Only import content that you own."); + .setName(t("Import TetraCube Data")) + .setDesc(t("Only import content that you own.")); const inputTetra = createEl("input", { attr: { type: "file", @@ -923,16 +927,16 @@ export default class StatblockSettingTab extends PluginSettingTab { this.display(); }; importTetra.addButton((b) => { - b.setButtonText("Choose File(s)").setTooltip( - "Import TetraCube Data" + b.setButtonText(t("Choose File(s)")).setTooltip( + t("Import TetraCube Data") ); b.buttonEl.addClass("statblock-file-upload"); b.buttonEl.appendChild(inputTetra); b.onClick(() => inputTetra.click()); }); const importPF2EMonsterTools = new Setting(importAdditional) - .setName("Import PF2eMonsterTools Data") - .setDesc("Only import content that you own."); + .setName(t("Import PF2eMonsterTools Data")) + .setDesc(t("Only import content that you own.")); const inputPF2EMonsterTools = createEl("input", { attr: { type: "file", @@ -951,8 +955,8 @@ export default class StatblockSettingTab extends PluginSettingTab { this.display(); }; importPF2EMonsterTools.addButton((b) => { - b.setButtonText("Choose File(s)").setTooltip( - "Import PF2EMonsterTools Data" + b.setButtonText(t("Choose File(s)")).setTooltip( + t("Import PF2EMonsterTools Data") ); b.buttonEl.addClass("statblock-file-upload"); b.buttonEl.appendChild(inputPF2EMonsterTools); @@ -960,8 +964,8 @@ export default class StatblockSettingTab extends PluginSettingTab { }); // import Pathbuilder const importPathbuilder = new Setting(importAdditional) - .setName("Import Pathbuilder Data") - .setDesc("Import a PC or NPC exported from Pathbuilder2e."); + .setName(t("Import Pathbuilder Data")) + .setDesc(t("Import a PC or NPC exported from Pathbuilder2e.")); const inputPathbuilder = createEl("input", { attr: { type: "file", @@ -980,8 +984,8 @@ export default class StatblockSettingTab extends PluginSettingTab { this.display(); }; importPathbuilder.addButton((b) => { - b.setButtonText("Choose File(s)").setTooltip( - "Import Pathbuilder Data" + b.setButtonText(t("Choose File(s)")).setTooltip( + t("Import Pathbuilder Data") ); b.buttonEl.addClass("statblock-file-upload"); b.buttonEl.appendChild(inputPathbuilder); @@ -991,16 +995,16 @@ export default class StatblockSettingTab extends PluginSettingTab { const importGeneric = new Setting(importAdditional) - .setName("Import Generic Data") + .setName(t("Import Generic Data")) .setDesc( createFragment((e) => { e.createSpan({ - text: "Import generic JSON files. JSON objects will be imported " + text: t("Import generic JSON files. JSON objects will be imported ") }); e.createEl("strong", { text: "as-is" }); - e.createSpan({ text: " and all objects must have the " }); + e.createSpan({ text: t(" and all objects must have the ") }); e.createEl("code", { text: "name" }); - e.createSpan({ text: " property." }); + e.createSpan({ text: t(" property.") }); }) ); const inputGeneric = createEl("input", { @@ -1021,7 +1025,7 @@ export default class StatblockSettingTab extends PluginSettingTab { this.display(); }; importGeneric.addButton((b) => { - b.setButtonText("Choose File(s)").setTooltip("Import Generic Data"); + b.setButtonText(t("Choose File(s)")).setTooltip(t("Import Generic Data")); b.buttonEl.addClass("statblock-file-upload"); b.buttonEl.appendChild(inputGeneric); b.onClick(() => inputGeneric.click()); @@ -1029,12 +1033,12 @@ export default class StatblockSettingTab extends PluginSettingTab { } generateMonsters(containerEl: HTMLDivElement) { containerEl.empty(); - new Setting(containerEl).setHeading().setName("Bestiary"); + new Setting(containerEl).setHeading().setName(t("Bestiary")); const additionalContainer = containerEl.createDiv( "statblock-additional-container statblock-monsters" ); new Setting(additionalContainer) - .setName("Add Creature") + .setName(t("Add Creature")) .addButton((b) => { b.setIcon("plus-with-circle").onClick(() => { const modal = new EditMonsterModal(this.plugin); @@ -1069,7 +1073,7 @@ class CreateStatblockModal extends FantasyStatblockModal { constructor( public plugin: StatBlockPlugin, layout: Layout = { - name: "Layout", + name: t("Layout"), blocks: [], id: nanoid() } @@ -1085,7 +1089,7 @@ class CreateStatblockModal extends FantasyStatblockModal { } display() { - this.titleEl.createSpan({ text: "Create Layout" }); + this.titleEl.createSpan({ text: t("Create Layout") }); this.creator = new LayoutEditor({ target: this.contentEl, props: { @@ -1110,7 +1114,7 @@ class ConfirmModal extends FantasyStatblockModal { super(plugin); } onOpen() { - this.titleEl.setText("Are you sure?"); + this.titleEl.setText(t("Are you sure?")); this.contentEl.createEl("p", { text: `This will delete ${this.filtered} creatures. This cannot be undone.` }); @@ -1153,10 +1157,10 @@ class ConfirmImport extends FantasyStatblockModal { this.contentEl.empty(); this.contentEl.addClass("confirm-modal"); this.contentEl.createEl("p", { - text: "This Layout includes JavaScript blocks. JavaScript blocks can execute code in your vault, which could cause loss or corruption of data." + text: t("This Layout includes JavaScript blocks. JavaScript blocks can execute code in your vault, which could cause loss or corruption of data.") }); this.contentEl.createEl("p", { - text: "Are you sure you want to import this layout?" + text: t("Are you sure you want to import this layout?") }); const buttonContainerEl = this.contentEl.createDiv( @@ -1164,7 +1168,7 @@ class ConfirmImport extends FantasyStatblockModal { ); buttonContainerEl.createEl("a").createEl("small", { cls: "dont-ask", - text: "Import and don't ask again" + text: t("Import and don't ask again") }).onclick = async () => { this.confirmed = true; this.plugin.settings.alwaysImport = true; @@ -1173,7 +1177,7 @@ class ConfirmImport extends FantasyStatblockModal { const buttonEl = buttonContainerEl.createDiv("confirm-buttons"); new ButtonComponent(buttonEl) - .setButtonText("Import") + .setButtonText(t("Import")) .setCta() .onClick(() => { this.confirmed = true; @@ -1181,7 +1185,7 @@ class ConfirmImport extends FantasyStatblockModal { }); buttonEl.createEl("a").createEl("small", { cls: "dont-ask", - text: "Cancel" + text: t("Cancel") }).onclick = () => { this.close(); }; From 826e4a164ebc361748194b68829f70b80ce31f3d Mon Sep 17 00:00:00 2001 From: Phillippe Caetano Date: Thu, 6 Nov 2025 23:36:39 -0300 Subject: [PATCH 3/9] feat: Translate statblock --- src/view/Statblock.svelte | 7 ++++--- src/view/ui/MarkdownHolder.svelte | 1 + src/view/ui/PropertyLine.svelte | 3 ++- src/view/ui/Saves.svelte | 3 ++- src/view/ui/SectionHeading.svelte | 3 ++- src/view/ui/Table.svelte | 3 ++- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/view/Statblock.svelte b/src/view/Statblock.svelte index cc9ffb40..bf040058 100644 --- a/src/view/Statblock.svelte +++ b/src/view/Statblock.svelte @@ -1,4 +1,5 @@ @@ -54,7 +55,7 @@ class:layout={block.type == "layout"} > {#if block.type == "javascript"} - JavaScript + {t("JavaScript")} {:else if block.type != "ifelse" && block.type != "collapse"} {/if} diff --git a/src/settings/layout/blocks/ui/Creator.svelte b/src/settings/layout/blocks/ui/Creator.svelte index d23f5f27..70140a25 100644 --- a/src/settings/layout/blocks/ui/Creator.svelte +++ b/src/settings/layout/blocks/ui/Creator.svelte @@ -15,6 +15,7 @@ import Rule from "src/view/ui/Rule.svelte"; import { type StatblockItem, TypeNames } from "src/layouts/layout.types"; import { setNodeIcon } from "src/util"; + import { t } from "src/util/i18n"; const dispatch = createEventDispatcher(); @@ -111,7 +112,7 @@ } else { new Menu() .addItem((item) => { - item.setTitle("Add") + item.setTitle(t("Add")) .setIcon("plus-with-circle") .onClick((e: MouseEvent | KeyboardEvent) => { add(block, evt); @@ -119,7 +120,7 @@ }) .addItem((item) => item - .setTitle("Edit") + .setTitle(t("Edit")) .setIcon("pencil") .onClick(() => { editBlock(block); @@ -127,7 +128,7 @@ ) .addItem((item) => item - .setTitle("Delete") + .setTitle(t("Delete")) .setIcon("trash") .onClick(() => trash(block)) ) @@ -138,13 +139,13 @@ const editIcon = (node: HTMLDivElement) => { new ExtraButtonComponent(node) .setIcon("pencil") - .setTooltip("Edit Block"); + .setTooltip(t("Edit Block")); }; const trashIcon = (node: HTMLDivElement) => { new ExtraButtonComponent(node) .setIcon("trash") - .setTooltip("Delete Block"); + .setTooltip(t("Delete Block")); }; @@ -209,7 +210,7 @@ {#if block.heading} {block.heading} {:else} - Collapse + {t("Collapse")} {/if} {#if "hasRule" in block && block.hasRule} -
+
{/if} diff --git a/src/settings/layout/blocks/ui/IfElseConditions.svelte b/src/settings/layout/blocks/ui/IfElseConditions.svelte index 5da44752..28f20a08 100644 --- a/src/settings/layout/blocks/ui/IfElseConditions.svelte +++ b/src/settings/layout/blocks/ui/IfElseConditions.svelte @@ -1,5 +1,6 @@ @@ -59,35 +60,35 @@
{/if} {#if block.conditioned}
{/if} {#if "callback" in block}
{/if} {#if ("dice" in block && block.dice) || ("diceCallback" in block && block.diceCallback?.length)}
{/if} {#if "markdown" in block && block.markdown}
{/if} diff --git a/src/settings/layout/blocks/ui/block.ts b/src/settings/layout/blocks/ui/block.ts index 1467d685..430453c5 100644 --- a/src/settings/layout/blocks/ui/block.ts +++ b/src/settings/layout/blocks/ui/block.ts @@ -31,6 +31,7 @@ import type StatBlockPlugin from "src/main"; import TableHeaders from "./TableHeaders.svelte"; import SubheadingProperty from "./SubheadingProperty.svelte"; import IfElseConditions from "./IfElseConditions.svelte"; +import { t } from "src/util/i18n"; import { editorFromTextArea, nanoid } from "src/util/util"; import { EditorView } from "@codemirror/view"; import type { Monster } from "index"; @@ -134,7 +135,7 @@ abstract class BlockModal< this.containerEl.addClass("statblock-edit-block"); } onOpen() { - this.titleEl.setText("Edit Block"); + this.titleEl.setText(t("Edit Block")); this.display(); } @@ -147,7 +148,7 @@ abstract class BlockModal< b .setCta() .setIcon("checkmark") - .setTooltip("Save") + .setTooltip(t("Save")) .onClick(() => { this.saved = true; this.close(); @@ -156,7 +157,7 @@ abstract class BlockModal< .addExtraButton((b) => b .setIcon("cross") - .setTooltip("Cancel") + .setTooltip(t("Cancel")) .onClick(() => { this.close(); }) @@ -170,9 +171,9 @@ class GroupModal extends BlockModal { async display() { this.contentEl.empty(); new Setting(this.contentEl) - .setName("Section Heading") + .setName(t("Section Heading")) .setDesc( - "This text will be used for the section heading. Can be left blank." + t("This text will be used for the section heading. Can be left blank.") ) .addText((t) => { t.setValue(this.block.heading).onChange( @@ -180,9 +181,9 @@ class GroupModal extends BlockModal { ); }); new Setting(this.contentEl) - .setName("Has Rule") + .setName(t("Has Rule")) .setDesc( - "If present, the block will have a horizontal rule placed after it." + t("If present, the block will have a horizontal rule placed after it.") ) .addToggle((t) => { t.setValue(this.block.hasRule).onChange( @@ -190,9 +191,9 @@ class GroupModal extends BlockModal { ); }); new Setting(this.contentEl) - .setName("CSS Container Class") + .setName(t("CSS Container Class")) .setDesc( - "All nested elements inside this group container will receive this CSS class. If blank, no class will be applied." + t("All nested elements inside this group container will receive this CSS class. If blank, no class will be applied.") ) .addText((t) => { t.setValue(this.block.cls).onChange( @@ -206,9 +207,9 @@ class GroupModal extends BlockModal { el.empty(); const block = this.block; new Setting(el) - .setName("Conditional") + .setName(t("Conditional")) .setDesc( - "The block will not be added if the associated properties are not present." + t("The block will not be added if the associated properties are not present.") ) .addToggle((t) => { t.setValue(block.conditioned).onChange((v) => { @@ -224,9 +225,9 @@ class CollapseModal extends BlockModal { async display() { this.contentEl.empty(); new Setting(this.contentEl) - .setName("Section Heading") + .setName(t("Section Heading")) .setDesc( - "This text will be used for the section heading. Can be left blank." + t("This text will be used for the section heading. Can be left blank.") ) .addText((t) => { t.setValue(this.block.heading).onChange( @@ -234,17 +235,17 @@ class CollapseModal extends BlockModal { ); }); new Setting(this.contentEl) - .setName("Open by Default") - .setDesc("The block will start open.") + .setName(t("Open by Default")) + .setDesc(t("The block will start open.")) .addToggle((t) => { t.setValue(this.block.open).onChange( (v) => (this.block.open = v) ); }); new Setting(this.contentEl) - .setName("Has Rule") + .setName(t("Has Rule")) .setDesc( - "If present, the block will have a horizontal rule placed after it." + t("If present, the block will have a horizontal rule placed after it.") ) .addToggle((t) => { t.setValue(this.block.hasRule).onChange( @@ -260,12 +261,12 @@ class JavaScriptModal extends BlockModal { this.contentEl.empty(); new Setting(this.contentEl) - .setName("JavaScript") + .setName(t("JavaScript")) .setHeading() .setDesc( createFragment((e) => { e.createSpan({ - text: "JavaScript blocks can be used to do highly advanced HTML elements. The JavaScript code will be provided the " + text: t("JavaScript blocks can be used to do highly advanced HTML elements. The JavaScript code will be provided the ") }); e.createEl("code", { text: "monster" @@ -275,7 +276,7 @@ class JavaScriptModal extends BlockModal { text: "property" }); e.createSpan({ - text: "parameters and should return a HTML element, which will be attached to the block's container element." + text: t("parameters and should return a HTML element, which will be attached to the block's container element.") }); }) ); @@ -317,7 +318,7 @@ class LayoutModal extends BlockModal { this.contentEl.empty(); new Setting(this.contentEl) - .setName("Layout to Insert") + .setName(t("Layout to Insert")) .addDropdown((d) => { for (const layout of this.plugin.manager.getAllLayouts()) { if (layout.id == this.layout) continue; @@ -392,7 +393,7 @@ abstract class EditorEnabledModal< this.plugin.saveSettings(); }; const summary = el.createEl("summary"); - new Setting(summary).setHeading().setName("Advanced Settings"); + new Setting(summary).setHeading().setName(t("Advanced Settings")); summary.createDiv("collapser").createDiv("handle"); this.buildAdvanced(el.createDiv()); } @@ -413,8 +414,8 @@ class ActionModal extends EditorEnabledModal { el.empty(); new Setting(el) - .setName("Icon") - .setDesc("Choose the icon to use for the button.") + .setName(t("Icon")) + .setDesc(t("Choose the icon to use for the button.")) .addText((t) => { t.setValue(this.block.icon); const icons = getIconIds().map((v) => @@ -439,8 +440,8 @@ class ActionModal extends EditorEnabledModal { b.setIcon(this.block.icon).setDisabled(true); }); new Setting(el) - .setName("Action") - .setDesc("Choose a Command to run when this action is executed.") + .setName(t("Action")) + .setDesc(t("Choose a Command to run when this action is executed.")) .addText((t) => { t.setValue(this.block.action); const commands = this.app.commands.listCommands(); @@ -465,23 +466,23 @@ class ActionModal extends EditorEnabledModal { new Setting(el) .setHeading() - .setName("Callback") + .setName(t("Callback")) .setDesc( createFragment((e) => { e.createSpan({ - text: "Executing the action will run the callback. Any registered commands will " + text: t("Executing the action will run the callback. Any registered commands will ") }); - e.createEl("strong", { text: "not" }); + e.createEl("strong", { text: t("not") }); e.createSpan({ - text: " be ran." + text: t(" be ran.") }); e.createEl("br"); e.createSpan({ - text: "The callback will receive the " + text: t("The callback will receive the ") }); e.createEl("code", { text: "monster" }); e.createSpan({ - text: " parameter. " + text: t(" parameter. ") }); }) ); @@ -503,9 +504,9 @@ class ActionModal extends EditorEnabledModal { class BasicModal extends EditorEnabledModal { addPropertyAsCssClassToggleSetting(el: HTMLDivElement) { new Setting(el) - .setName("Add Property as CSS Class") + .setName(t("Add Property as CSS Class")) .setDesc( - "Disable this to prevent adding the property to the containing HTML element as a CSS class. This can be used to avoid collisions with native Obsidian CSS." + t("Disable this to prevent adding the property to the containing HTML element as a CSS class. This can be used to avoid collisions with native Obsidian CSS.") ) .addToggle((t) => { t.setValue(!this.block.doNotAddClass).onChange((v) => { @@ -517,7 +518,7 @@ class BasicModal extends EditorEnabledModal { buildProperties(el: HTMLDivElement) { el.empty(); const block = this.block; - new Setting(el).setName("Link Monster Property").addText((t) => + new Setting(el).setName(t("Link Monster Property")).addText((t) => t.setValue(block.properties[0]).onChange((v) => { block.properties[0] = v; }) @@ -528,29 +529,29 @@ class BasicModal extends EditorEnabledModal { if (this.plugin.canUseDiceRoller) { new Setting(el) .setHeading() - .setName("Dice Callback") + .setName(t("Dice Callback")) .setDesc( createFragment((e) => { e.createSpan({ - text: "The block will run the callback and use the returned values for the dice strings." + text: t("The block will run the callback and use the returned values for the dice strings.") }); e.createEl("br"); e.createSpan({ - text: "The callback will receive the " + text: t("The callback will receive the ") }); e.createEl("code", { text: "monster" }); - e.createSpan({ text: " and " }); + e.createSpan({ text: t(" and ") }); e.createEl("code", { text: "property" }); e.createSpan({ - text: "parameters. Dice callbacks should return an array of strings and objects, with the objects defining the dice rolls:" + text: t("parameters. Dice callbacks should return an array of strings and objects, with the objects defining the dice rolls:") }); e.createEl("br"); MarkdownRenderer.render( this.plugin.app, `\`\`\`ts interface DiceCallbackObject { - text: string // string to be parsed into a dice roll - original?: string // optional, shown in parenthesis + text: string // ${t("string to be parsed into a dice roll")} + original?: string // ${t("optional, shown in parenthesis")} } \`\`\``, e.createDiv(), @@ -559,13 +560,13 @@ interface DiceCallbackObject { ); e.createEl("br"); - e.createEl("span", { text: "For example: " }); + e.createEl("span", { text: t("For example: ") }); e.createEl("br"); MarkdownRenderer.render( this.plugin.app, `\`\`\`ts const diceText = monster.stats[5] + "d20 + 2"; -return ["The monster guesses you have: ", { text: diceText }, " freckles."]; +return ["${t("The monster guesses you have: ")}", { text: diceText }, "${t(" freckles.")}"]; \`\`\``, e.createDiv(), "", @@ -598,9 +599,9 @@ return ["The monster guesses you have: ", { text: diceText }, " freckles."]; el.empty(); const block = this.block; new Setting(el) - .setName("Conditional") + .setName(t("Conditional")) .setDesc( - "The block will not be added if the associated properties are not present." + t("The block will not be added if the associated properties are not present.") ) .addToggle((t) => { t.setValue(block.conditioned).onChange((v) => { @@ -611,8 +612,8 @@ return ["The monster guesses you have: ", { text: diceText }, " freckles."]; }); if (!this.block.conditioned) { new Setting(el) - .setName("Fallback") - .setDesc("If not present, this text will be displayed.") + .setName(t("Fallback")) + .setDesc(t("If not present, this text will be displayed.")) .addText((t) => { if (!block.fallback) { block.fallback = "-"; @@ -623,9 +624,9 @@ return ["The monster guesses you have: ", { text: diceText }, " freckles."]; }); } new Setting(el) - .setName("Has Rule") + .setName(t("Has Rule")) .setDesc( - "If present, the block will have a horizontal rule placed after it." + t("If present, the block will have a horizontal rule placed after it.") ) .addToggle((t) => { t.setValue(block.hasRule).onChange((v) => (block.hasRule = v)); @@ -636,9 +637,9 @@ return ["The monster guesses you have: ", { text: diceText }, " freckles."]; const block = this.block; if (this.plugin.canUseDiceRoller) { new Setting(el) - .setName("Parse for Dice") + .setName(t("Parse for Dice")) .setDesc( - "The plugin will attempt to add dice rollers as specified." + t("The plugin will attempt to add dice rollers as specified.") ) .addToggle((t) => @@ -649,9 +650,9 @@ return ["The monster guesses you have: ", { text: diceText }, " freckles."]; ); if (block.dice) { new Setting(el.createDiv()) - .setName("Link Dice to Property") + .setName(t("Link Dice to Property")) .setDesc( - "The dice roller will parse this property instead of the original." + t("The dice roller will parse this property instead of the original.") ) .addText((t) => { t.setValue(`${block.diceProperty}`).onChange((v) => { @@ -687,8 +688,8 @@ class HeadingModal extends BasicModal { buildProperties(el: HTMLDivElement): void { super.buildProperties(el); new Setting(el) - .setName("Header Size") - .setDesc("The heading will use this size.") + .setName(t("Header Size")) + .setDesc(t("The heading will use this size.")) .addDropdown((d) => { if (!this.block.size) { this.block.size == 1; @@ -711,25 +712,25 @@ class PropertyModal extends MarkdownEnabledModal { super.buildAdvanced(el); new Setting(el) .setHeading() - .setName("Callback") + .setName(t("Callback")) .setDesc( createFragment((e) => { e.createSpan({ - text: "The block will run the callback and use the returned string as the property." + text: t("The block will run the callback and use the returned string as the property.") }); e.createEl("br"); e.createSpan({ - text: "The callback will receive the " + text: t("The callback will receive the ") }); e.createEl("code", { text: "monster" }); e.createSpan({ - text: " parameter. The callback should return a string. For example: " + text: t(" parameter. The callback should return a string. For example: ") }); e.createEl("code", { text: "return monster.name" }); e.createEl("br"); e.createEl("strong", { - text: "Please Note: This will not run if a dice callback is provided." + text: t("Please Note: This will not run if a dice callback is provided.") }); }) ); @@ -755,8 +756,8 @@ class PropertyModal extends MarkdownEnabledModal { super.buildProperties(el); super.addPropertyAsCssClassToggleSetting(el); new Setting(el) - .setName("Display Text") - .setDesc("This text will be used for the property name.") + .setName(t("Display Text")) + .setDesc(t("This text will be used for the property name.")) .addText((t) => { t.setValue(this.block.display).onChange( (v) => (this.block.display = v) @@ -769,8 +770,8 @@ class SavesModal extends MarkdownEnabledModal { super.buildProperties(el); super.addPropertyAsCssClassToggleSetting(el); new Setting(el) - .setName("Display Text") - .setDesc("This text will be used for the property name.") + .setName(t("Display Text")) + .setDesc(t("This text will be used for the property name.")) .addText((t) => { t.setValue(this.block.display).onChange( (v) => (this.block.display = v) @@ -781,27 +782,27 @@ class SavesModal extends MarkdownEnabledModal { super.buildAdvanced(el); new Setting(el) .setHeading() - .setName("Callback") + .setName(t("Callback")) .setDesc( createFragment((e) => { e.createSpan({ - text: "The block will run the callback on each save object and use the returned object as the save." + text: t("The block will run the callback on each save object and use the returned object as the save.") }); e.createEl("br"); e.createSpan({ - text: "The callback will receive the " + text: t("The callback will receive the ") }); e.createEl("code", { text: "monster" }); - e.createSpan({ text: " and " }); + e.createSpan({ text: t(" and ") }); e.createEl("code", { text: "property" }); e.createSpan({ - text: " parameters. The callback should return an object with a single key and value. For example: " + text: t(" parameters. The callback should return an object with a single key and value. For example: ") }); e.createEl("code", { text: "return {\"fort\": property.fortitude}" }); e.createEl("br"); e.createEl("strong", { - text: "Please Note: This will not run if a dice callback is provided." + text: t("Please Note: This will not run if a dice callback is provided.") }); }) ); @@ -824,9 +825,9 @@ class SpellsModal extends MarkdownEnabledModal { buildProperties(el: HTMLDivElement): void { super.buildProperties(el); new Setting(el) - .setName("Trait Name") + .setName(t("Trait Name")) .setDesc( - "Name to display for the Spellcasting trait. Defaults to Spellcasting if not provided." + t("Name to display for the Spellcasting trait. Defaults to Spellcasting if not provided.") ) .addText((t) => { t.setValue(this.block.heading).onChange( @@ -843,7 +844,7 @@ class SubheadingModal extends BasicModal { let tempProp = ""; new Setting(container) .setHeading() - .setName("Link Monster Properties") + .setName(t("Link Monster Properties")) .addText((t) => t .setPlaceholder("property") @@ -853,7 +854,7 @@ class SubheadingModal extends BasicModal { .addExtraButton((b) => b.setIcon("plus-with-circle").onClick(() => { if (!tempProp || !tempProp.length) { - new Notice("A valid property must be supplied."); + new Notice(t("A valid property must be supplied.")); return; } block.properties.push(tempProp); @@ -878,8 +879,8 @@ class SubheadingModal extends BasicModal { el.empty(); new Setting(el) - .setName("Separator") - .setDesc("Text separating properties") + .setName(t("Separator")) + .setDesc(t("Text separating properties")) .addText((t) => { t.setValue(this.block.separator).onChange((v) => { //If onchange(v) parameter is empty, get default ", " or v value @@ -898,19 +899,19 @@ class TableModal extends BasicModal { super.buildAdvanced(el); new Setting(el) .setHeading() - .setName("Ability Modifier Calculation") + .setName(t("Ability Modifier Calculation")) .setDesc( createFragment((e) => { e.createSpan({ - text: "Allows a custom modifier for the stat." + text: t("Allows a custom modifier for the stat.") }); e.createEl("br"); - e.createSpan({ text: "Variables " }); + e.createSpan({ text: t("Variables ") }); e.createEl("code", { text: "stat" }); - e.createSpan({ text: " and " }); + e.createSpan({ text: t(" and ") }); e.createEl("code", { text: "monster" }); e.createSpan({ - text: "are accessible, use these to calculate the modifier." + text: t("are accessible, use these to calculate the modifier.") }); }) ); @@ -936,17 +937,17 @@ class TableModal extends BasicModal { let tempProp = ""; new Setting(container) .setHeading() - .setName("Table Headers") - .addText((t) => - t - .setPlaceholder("header") + .setName(t("Table Headers")) + .addText((x) => + x + .setPlaceholder(t("header")) .setValue(tempProp) .onChange((v) => (tempProp = v)) ) .addExtraButton((b) => b.setIcon("plus-with-circle").onClick(() => { if (!tempProp || !tempProp.length) { - new Notice("A valid property must be supplied."); + new Notice(t("A valid property must be supplied.")); return; } this.block.headers.push(tempProp); @@ -963,9 +964,9 @@ class TableModal extends BasicModal { this.block.headers = [...(e.detail?.map((v) => v.name) ?? [])]; }); new Setting(el) - .setName("Calculate Modifiers") + .setName(t("Calculate Modifiers")) .setDesc( - "The block will attempt to calculate modifiers for table values." + t("The block will attempt to calculate modifiers for table values.") ) .addToggle((t) => { t.setValue(this.block.calculate).onChange((v) => { @@ -980,9 +981,9 @@ class TraitsModal extends MarkdownEnabledModal { super.buildProperties(el); super.addPropertyAsCssClassToggleSetting(el); new Setting(el) - .setName("Use Monster Property for Heading") + .setName(t("Use Monster Property for Heading")) .setDesc( - "The Section heading will be set to the value of the specified property." + t("The Section heading will be set to the value of the specified property.") ) .addToggle((t) => { t.setValue(this.block.headingProp).onChange((v) => { @@ -994,8 +995,8 @@ class TraitsModal extends MarkdownEnabledModal { .setName("Section Heading") .setDesc( this.block.headingProp - ? "The section will use this property for the section heading. If the property does not exist or is blank, the section heading will not appear." - : "This text will be used for the section heading. Can be left blank." + ? t("The section will use this property for the section heading. If the property does not exist or is blank, the section heading will not appear.") + : t("This text will be used for the section heading. Can be left blank.") ) .addText((t) => { t.setValue(this.block.heading).onChange( @@ -1003,15 +1004,15 @@ class TraitsModal extends MarkdownEnabledModal { ); }); const subheading = new Setting(el) - .setName("Section Subheading Text") + .setName(t("Section Subheading Text")) .setDesc( createFragment((e) => { e.createSpan({ - text: "Text entered here will appear directly after the section heading, before the actual traits. Use " + text: t("Text entered here will appear directly after the section heading, before the actual traits. Use ") }); e.createEl("code", { text: "{{monster}}" }); e.createSpan({ - text: " to insert the current monster's name." + text: t(" to insert the current monster's name.") }); }) ); @@ -1025,27 +1026,27 @@ class TraitsModal extends MarkdownEnabledModal { super.buildAdvanced(el); new Setting(el) .setHeading() - .setName("Callback") + .setName(t("Callback")) .setDesc( createFragment((e) => { e.createSpan({ - text: "The block will run the callback on each trait and use the returned string as the trait description." + text: t("The block will run the callback on each trait and use the returned string as the trait description.") }); e.createEl("br"); e.createSpan({ - text: "The callback will receive the " + text: t("The callback will receive the ") }); e.createEl("code", { text: "monster" }); e.createSpan({ text: " and " }); e.createEl("code", { text: "property" }); e.createSpan({ - text: " parameters. The callback should return a string. For example: " + text: t(" parameters. The callback should return a string. For example: ") }); e.createEl("code", { text: "return monster.name" }); e.createEl("br"); e.createEl("strong", { - text: "Please Note: This will not run if a dice callback is provided." + text: t("Please Note: This will not run if a dice callback is provided.") }); }) ); @@ -1069,13 +1070,13 @@ class TextModal extends MarkdownEnabledModal { super.buildAdvanced(el); new Setting(el) .setHeading() - .setName("Text to Show") + .setName(t("Text to Show")) .setDesc( createFragment((e) => { - e.createSpan({ text: "The block will " }); - e.createEl("strong", { text: "always" }); + e.createSpan({ text: t("The block will ") }); + e.createEl("strong", { text: t("always") }); e.createSpan({ - text: " display the text entered here." + text: t(" display the text entered here.") }); }) ); @@ -1086,9 +1087,9 @@ class TextModal extends MarkdownEnabledModal { buildProperties(el: HTMLDivElement): void { super.buildProperties(el); new Setting(el) - .setName("Use Monster Property for Heading") + .setName(t("Use Monster Property for Heading")) .setDesc( - "The Section heading will be set to the value of the specified property." + t("The Section heading will be set to the value of the specified property.") ) .addToggle((t) => { t.setValue(this.block.headingProp).onChange((v) => { @@ -1097,11 +1098,11 @@ class TextModal extends MarkdownEnabledModal { }); }); new Setting(el) - .setName("Section Heading") + .setName(t("Section Heading")) .setDesc( this.block.headingProp - ? "The section will use this property for the section heading. If the property does not exist or is blank, the section heading will not appear." - : "This text will be used for the section heading. Can be left blank." + ? t("The section will use this property for the section heading. If the property does not exist or is blank, the section heading will not appear.") + : t("This text will be used for the section heading. Can be left blank.") ) .addText((t) => { t.setValue(this.block.heading).onChange( diff --git a/src/settings/layout/previewer/Previewer.svelte b/src/settings/layout/previewer/Previewer.svelte index 645870dc..e6889abd 100644 --- a/src/settings/layout/previewer/Previewer.svelte +++ b/src/settings/layout/previewer/Previewer.svelte @@ -12,6 +12,7 @@ import { MonsterSuggestionModal } from "src/util/creature"; import type { Monster } from "index"; import { buildTextArea, setNodeIcon } from "src/util"; + import { t } from "src/util/i18n"; import type { EditorView } from "@codemirror/view"; import StatBlockRenderer from "src/view/statblock"; import { derived, writable } from "svelte/store"; @@ -48,7 +49,7 @@ }); const search = (node: HTMLElement) => { const search = new SearchComponent(node).setPlaceholder( - "Find a creature" + t("Find a creature") ); const suggester = new MonsterSuggestionModal( plugin.app, @@ -108,12 +109,12 @@ }); }; const settingsDesc = derived([mode, scale], ([mode, scale]) => { - const desc = [`Scale: ${scale}`]; + const desc = [`${t("Scale:")} ${scale}`]; if (mode === ThemeMode.Light) { - desc.push("Mode: Light"); + desc.push(t("Mode: Light")); } if (mode === ThemeMode.Dark) { - desc.push("Mode: Dark"); + desc.push(t("Mode: Dark")); } return desc.join(", "); }); @@ -126,8 +127,7 @@ style={`--scale: ${$scale}`} >
- Select a creature to preview the layout, or enter your own definition - below. + {t("Select a creature to preview the layout, or enter your own definition below.")}
@@ -138,18 +138,18 @@
-
Set theme mode
+
{t("Set theme mode")}
@@ -157,8 +157,8 @@
-
Scale preview
-
Current: {$scale}
+
{t("Scale preview")}
+
{t("Current:")} {$scale}
{ if (!detail.name) { - new Notice("Creatures must be given a name."); + new Notice(t("Creatures must be given a name.")); return; } await this.plugin.updateMonster(this.monster as Monster, detail); diff --git a/src/view/Statblock.svelte b/src/view/Statblock.svelte index 02f9fd8d..b85b4dbf 100644 --- a/src/view/Statblock.svelte +++ b/src/view/Statblock.svelte @@ -120,10 +120,10 @@ .onClick(async () => { try { await navigator.clipboard.writeText(stringifyYaml(monster)); - new Notice("Creature YAML copied to clipboard"); + new Notice(t("Creature YAML copied to clipboard")); } catch (e: unknown) { new Notice( - `There was an issue copying the yaml:\n\n${(e as Error).message}` + `${t("There was an issue copying the yaml:")}\n\n${(e as Error).message}` ); } }); @@ -138,7 +138,7 @@ menu.addItem((item) => item .setIcon("reset") - .setTitle("Reset Dice") + .setTitle(t("Reset Dice")) .onClick(() => { reset.set(true); reset.set(false); @@ -199,7 +199,7 @@ {/key} {:else} - Invalid monster. + {t("Invalid monster.")} {/if} {/key}
diff --git a/src/view/statblock.ts b/src/view/statblock.ts index f47b6cd1..e637c6e0 100644 --- a/src/view/statblock.ts +++ b/src/view/statblock.ts @@ -26,6 +26,7 @@ import type { StatblockItem } from "src/layouts/layout.types"; import { append } from "src/util/util"; +import { t } from "src/util/i18n"; import { Linkifier } from "src/parser/linkify"; import { Bestiary } from "src/bestiary/bestiary"; import copy from "fast-copy"; @@ -391,13 +392,13 @@ export default class StatBlockRenderer extends MarkdownRenderChild { Bestiary.hasCreature(this.monster.name) && !(await confirmWithModal( this.plugin.app, - "This will overwrite an existing monster in settings. Are you sure?" + t("This will overwrite an existing monster in settings. Are you sure?") )) ) return; this.plugin.saveMonster({ ...fastCopy(this.monster), - source: this.monster.source ?? "Homebrew", + source: this.monster.source ?? t("Homebrew"), layout: this.layout.name } as Monster); }); @@ -440,8 +441,8 @@ export async function confirmWithModal( app: App, text: string, buttons: { cta: string; secondary: string } = { - cta: "Yes", - secondary: "No" + cta: t("Yes"), + secondary: t("No") } ): Promise { return new Promise((resolve, reject) => { diff --git a/src/view/ui/Action.svelte b/src/view/ui/Action.svelte index 1c1a9cf9..1891f6a3 100644 --- a/src/view/ui/Action.svelte +++ b/src/view/ui/Action.svelte @@ -1,5 +1,6 @@ diff --git a/src/view/ui/Traits.svelte b/src/view/ui/Traits.svelte index c643827e..53c6bb42 100644 --- a/src/view/ui/Traits.svelte +++ b/src/view/ui/Traits.svelte @@ -1,6 +1,7 @@