diff --git a/.yarn/cache/@babel-code-frame-npm-7.29.7-cc910f9962-21b12fe235.zip b/.yarn/cache/@babel-code-frame-npm-7.29.7-cc910f9962-21b12fe235.zip new file mode 100644 index 00000000000..2696bc6dfe5 Binary files /dev/null and b/.yarn/cache/@babel-code-frame-npm-7.29.7-cc910f9962-21b12fe235.zip differ diff --git a/.yarn/cache/@babel-compat-data-npm-7.29.7-6487d724ba-4424f8fb72.zip b/.yarn/cache/@babel-compat-data-npm-7.29.7-6487d724ba-4424f8fb72.zip new file mode 100644 index 00000000000..c261d039c59 Binary files /dev/null and b/.yarn/cache/@babel-compat-data-npm-7.29.7-6487d724ba-4424f8fb72.zip differ diff --git a/.yarn/cache/@babel-core-npm-7.29.7-78bc20dbf7-95149e98ff.zip b/.yarn/cache/@babel-core-npm-7.29.7-78bc20dbf7-95149e98ff.zip new file mode 100644 index 00000000000..81e43a8eff3 Binary files /dev/null and b/.yarn/cache/@babel-core-npm-7.29.7-78bc20dbf7-95149e98ff.zip differ diff --git a/.yarn/cache/@babel-generator-npm-7.29.7-b512136a1f-6bb8f4dc06.zip b/.yarn/cache/@babel-generator-npm-7.29.7-b512136a1f-6bb8f4dc06.zip new file mode 100644 index 00000000000..088e00ac6fb Binary files /dev/null and b/.yarn/cache/@babel-generator-npm-7.29.7-b512136a1f-6bb8f4dc06.zip differ diff --git a/.yarn/cache/@babel-helper-annotate-as-pure-npm-7.29.7-23c838e131-acd9e128de.zip b/.yarn/cache/@babel-helper-annotate-as-pure-npm-7.29.7-23c838e131-acd9e128de.zip new file mode 100644 index 00000000000..e8f68ddbd74 Binary files /dev/null and b/.yarn/cache/@babel-helper-annotate-as-pure-npm-7.29.7-23c838e131-acd9e128de.zip differ diff --git a/.yarn/cache/@babel-helper-compilation-targets-npm-7.29.7-7cb31cc38d-f60a943937.zip b/.yarn/cache/@babel-helper-compilation-targets-npm-7.29.7-7cb31cc38d-f60a943937.zip new file mode 100644 index 00000000000..0572c3af2bd Binary files /dev/null and b/.yarn/cache/@babel-helper-compilation-targets-npm-7.29.7-7cb31cc38d-f60a943937.zip differ diff --git a/.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.29.7-d2ad5f51e0-c954e4bfe4.zip b/.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.29.7-d2ad5f51e0-c954e4bfe4.zip new file mode 100644 index 00000000000..a65f1fbc688 Binary files /dev/null and b/.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.29.7-d2ad5f51e0-c954e4bfe4.zip differ diff --git a/.yarn/cache/@babel-helper-create-regexp-features-plugin-npm-7.29.7-afcf0ca875-702a34db6c.zip b/.yarn/cache/@babel-helper-create-regexp-features-plugin-npm-7.29.7-afcf0ca875-702a34db6c.zip new file mode 100644 index 00000000000..4ffbe0afaf9 Binary files /dev/null and b/.yarn/cache/@babel-helper-create-regexp-features-plugin-npm-7.29.7-afcf0ca875-702a34db6c.zip differ diff --git a/.yarn/cache/@babel-helper-define-polyfill-provider-npm-0.6.8-65b6b31041-39fef64ade.zip b/.yarn/cache/@babel-helper-define-polyfill-provider-npm-0.6.8-65b6b31041-39fef64ade.zip new file mode 100644 index 00000000000..634088f2763 Binary files /dev/null and b/.yarn/cache/@babel-helper-define-polyfill-provider-npm-0.6.8-65b6b31041-39fef64ade.zip differ diff --git a/.yarn/cache/@babel-helper-globals-npm-7.29.7-bb76425ef5-6deaf9846a.zip b/.yarn/cache/@babel-helper-globals-npm-7.29.7-bb76425ef5-6deaf9846a.zip new file mode 100644 index 00000000000..0f34438c6e9 Binary files /dev/null and b/.yarn/cache/@babel-helper-globals-npm-7.29.7-bb76425ef5-6deaf9846a.zip differ diff --git a/.yarn/cache/@babel-helper-member-expression-to-functions-npm-7.29.7-6e307e31eb-79d5f095b4.zip b/.yarn/cache/@babel-helper-member-expression-to-functions-npm-7.29.7-6e307e31eb-79d5f095b4.zip new file mode 100644 index 00000000000..29669b8a7b5 Binary files /dev/null and b/.yarn/cache/@babel-helper-member-expression-to-functions-npm-7.29.7-6e307e31eb-79d5f095b4.zip differ diff --git a/.yarn/cache/@babel-helper-module-imports-npm-7.29.7-c44b78302c-ad5a768fc9.zip b/.yarn/cache/@babel-helper-module-imports-npm-7.29.7-c44b78302c-ad5a768fc9.zip new file mode 100644 index 00000000000..dc4344fcc81 Binary files /dev/null and b/.yarn/cache/@babel-helper-module-imports-npm-7.29.7-c44b78302c-ad5a768fc9.zip differ diff --git a/.yarn/cache/@babel-helper-module-transforms-npm-7.29.7-50e1c84dbd-484f6d0297.zip b/.yarn/cache/@babel-helper-module-transforms-npm-7.29.7-50e1c84dbd-484f6d0297.zip new file mode 100644 index 00000000000..2776228d563 Binary files /dev/null and b/.yarn/cache/@babel-helper-module-transforms-npm-7.29.7-50e1c84dbd-484f6d0297.zip differ diff --git a/.yarn/cache/@babel-helper-optimise-call-expression-npm-7.29.7-a1156041fe-6b477e01b4.zip b/.yarn/cache/@babel-helper-optimise-call-expression-npm-7.29.7-a1156041fe-6b477e01b4.zip new file mode 100644 index 00000000000..7d0d5a42d6f Binary files /dev/null and b/.yarn/cache/@babel-helper-optimise-call-expression-npm-7.29.7-a1156041fe-6b477e01b4.zip differ diff --git a/.yarn/cache/@babel-helper-plugin-utils-npm-7.29.7-b50f319ba2-b0a183abcc.zip b/.yarn/cache/@babel-helper-plugin-utils-npm-7.29.7-b50f319ba2-b0a183abcc.zip new file mode 100644 index 00000000000..ad0f1301047 Binary files /dev/null and b/.yarn/cache/@babel-helper-plugin-utils-npm-7.29.7-b50f319ba2-b0a183abcc.zip differ diff --git a/.yarn/cache/@babel-helper-remap-async-to-generator-npm-7.29.7-6476c9e054-98338ad6e3.zip b/.yarn/cache/@babel-helper-remap-async-to-generator-npm-7.29.7-6476c9e054-98338ad6e3.zip new file mode 100644 index 00000000000..8edbc39c6dc Binary files /dev/null and b/.yarn/cache/@babel-helper-remap-async-to-generator-npm-7.29.7-6476c9e054-98338ad6e3.zip differ diff --git a/.yarn/cache/@babel-helper-replace-supers-npm-7.29.7-d22238da67-f7eb9a6b03.zip b/.yarn/cache/@babel-helper-replace-supers-npm-7.29.7-d22238da67-f7eb9a6b03.zip new file mode 100644 index 00000000000..e9a52df942d Binary files /dev/null and b/.yarn/cache/@babel-helper-replace-supers-npm-7.29.7-d22238da67-f7eb9a6b03.zip differ diff --git a/.yarn/cache/@babel-helper-skip-transparent-expression-wrappers-npm-7.29.7-6a7aa12dea-a5800bfcdc.zip b/.yarn/cache/@babel-helper-skip-transparent-expression-wrappers-npm-7.29.7-6a7aa12dea-a5800bfcdc.zip new file mode 100644 index 00000000000..64fac34389f Binary files /dev/null and b/.yarn/cache/@babel-helper-skip-transparent-expression-wrappers-npm-7.29.7-6a7aa12dea-a5800bfcdc.zip differ diff --git a/.yarn/cache/@babel-helper-string-parser-npm-7.29.7-87998d618e-4c229d2c22.zip b/.yarn/cache/@babel-helper-string-parser-npm-7.29.7-87998d618e-4c229d2c22.zip new file mode 100644 index 00000000000..6207d77e336 Binary files /dev/null and b/.yarn/cache/@babel-helper-string-parser-npm-7.29.7-87998d618e-4c229d2c22.zip differ diff --git a/.yarn/cache/@babel-helper-validator-identifier-npm-7.29.7-9939aac13d-cc7779e96f.zip b/.yarn/cache/@babel-helper-validator-identifier-npm-7.29.7-9939aac13d-cc7779e96f.zip new file mode 100644 index 00000000000..7323864a091 Binary files /dev/null and b/.yarn/cache/@babel-helper-validator-identifier-npm-7.29.7-9939aac13d-cc7779e96f.zip differ diff --git a/.yarn/cache/@babel-helper-validator-option-npm-7.29.7-635d603818-aeb6aa966f.zip b/.yarn/cache/@babel-helper-validator-option-npm-7.29.7-635d603818-aeb6aa966f.zip new file mode 100644 index 00000000000..5139734ce73 Binary files /dev/null and b/.yarn/cache/@babel-helper-validator-option-npm-7.29.7-635d603818-aeb6aa966f.zip differ diff --git a/.yarn/cache/@babel-helper-wrap-function-npm-7.29.7-1de4292536-2e6dfca94a.zip b/.yarn/cache/@babel-helper-wrap-function-npm-7.29.7-1de4292536-2e6dfca94a.zip new file mode 100644 index 00000000000..8bb5c0cc3f3 Binary files /dev/null and b/.yarn/cache/@babel-helper-wrap-function-npm-7.29.7-1de4292536-2e6dfca94a.zip differ diff --git a/.yarn/cache/@babel-helpers-npm-7.29.7-97e81ccfb9-b5c4ed0ce5.zip b/.yarn/cache/@babel-helpers-npm-7.29.7-97e81ccfb9-b5c4ed0ce5.zip new file mode 100644 index 00000000000..2a836ccc78d Binary files /dev/null and b/.yarn/cache/@babel-helpers-npm-7.29.7-97e81ccfb9-b5c4ed0ce5.zip differ diff --git a/.yarn/cache/@babel-parser-npm-7.29.7-90d40e76ce-56f4c32a37.zip b/.yarn/cache/@babel-parser-npm-7.29.7-90d40e76ce-56f4c32a37.zip new file mode 100644 index 00000000000..aa492c188e4 Binary files /dev/null and b/.yarn/cache/@babel-parser-npm-7.29.7-90d40e76ce-56f4c32a37.zip differ diff --git a/.yarn/cache/@babel-plugin-bugfix-firefox-class-in-computed-class-key-npm-7.29.7-f6dbdc151b-83cca77d17.zip b/.yarn/cache/@babel-plugin-bugfix-firefox-class-in-computed-class-key-npm-7.29.7-f6dbdc151b-83cca77d17.zip new file mode 100644 index 00000000000..6bd03cd0351 Binary files /dev/null and b/.yarn/cache/@babel-plugin-bugfix-firefox-class-in-computed-class-key-npm-7.29.7-f6dbdc151b-83cca77d17.zip differ diff --git a/.yarn/cache/@babel-plugin-bugfix-safari-class-field-initializer-scope-npm-7.29.7-6fe206652b-ad06de66cc.zip b/.yarn/cache/@babel-plugin-bugfix-safari-class-field-initializer-scope-npm-7.29.7-6fe206652b-ad06de66cc.zip new file mode 100644 index 00000000000..08758d5409c Binary files /dev/null and b/.yarn/cache/@babel-plugin-bugfix-safari-class-field-initializer-scope-npm-7.29.7-6fe206652b-ad06de66cc.zip differ diff --git a/.yarn/cache/@babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression-npm-7.29.7-77f6c36cc3-2189a2a648.zip b/.yarn/cache/@babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression-npm-7.29.7-77f6c36cc3-2189a2a648.zip new file mode 100644 index 00000000000..f95504f0611 Binary files /dev/null and b/.yarn/cache/@babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression-npm-7.29.7-77f6c36cc3-2189a2a648.zip differ diff --git a/.yarn/cache/@babel-plugin-bugfix-safari-rest-destructuring-rhs-array-npm-7.29.7-1aa066da6a-a9bd13c260.zip b/.yarn/cache/@babel-plugin-bugfix-safari-rest-destructuring-rhs-array-npm-7.29.7-1aa066da6a-a9bd13c260.zip new file mode 100644 index 00000000000..70b11bac9a1 Binary files /dev/null and b/.yarn/cache/@babel-plugin-bugfix-safari-rest-destructuring-rhs-array-npm-7.29.7-1aa066da6a-a9bd13c260.zip differ diff --git a/.yarn/cache/@babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining-npm-7.29.7-3e65f1fd55-76a494ec4f.zip b/.yarn/cache/@babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining-npm-7.29.7-3e65f1fd55-76a494ec4f.zip new file mode 100644 index 00000000000..4772873aa23 Binary files /dev/null and b/.yarn/cache/@babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining-npm-7.29.7-3e65f1fd55-76a494ec4f.zip differ diff --git a/.yarn/cache/@babel-plugin-bugfix-v8-static-class-fields-redefine-readonly-npm-7.29.7-f11f25799d-7a58b4b32f.zip b/.yarn/cache/@babel-plugin-bugfix-v8-static-class-fields-redefine-readonly-npm-7.29.7-f11f25799d-7a58b4b32f.zip new file mode 100644 index 00000000000..b047adcc3ea Binary files /dev/null and b/.yarn/cache/@babel-plugin-bugfix-v8-static-class-fields-redefine-readonly-npm-7.29.7-f11f25799d-7a58b4b32f.zip differ diff --git a/.yarn/cache/@babel-plugin-proposal-decorators-npm-7.29.7-6c77327c8e-4a92b511af.zip b/.yarn/cache/@babel-plugin-proposal-decorators-npm-7.29.7-6c77327c8e-4a92b511af.zip new file mode 100644 index 00000000000..487291452ec Binary files /dev/null and b/.yarn/cache/@babel-plugin-proposal-decorators-npm-7.29.7-6c77327c8e-4a92b511af.zip differ diff --git a/.yarn/cache/@babel-plugin-proposal-export-default-from-npm-7.29.7-6df99ee7f6-373ba179cb.zip b/.yarn/cache/@babel-plugin-proposal-export-default-from-npm-7.29.7-6df99ee7f6-373ba179cb.zip new file mode 100644 index 00000000000..9c669097c14 Binary files /dev/null and b/.yarn/cache/@babel-plugin-proposal-export-default-from-npm-7.29.7-6df99ee7f6-373ba179cb.zip differ diff --git a/.yarn/cache/@babel-plugin-syntax-decorators-npm-7.29.7-14d3d5c32e-3a49c261fb.zip b/.yarn/cache/@babel-plugin-syntax-decorators-npm-7.29.7-14d3d5c32e-3a49c261fb.zip new file mode 100644 index 00000000000..08dd3d06d2e Binary files /dev/null and b/.yarn/cache/@babel-plugin-syntax-decorators-npm-7.29.7-14d3d5c32e-3a49c261fb.zip differ diff --git a/.yarn/cache/@babel-plugin-syntax-flow-npm-7.29.7-d41f3a60ad-3e03792bb2.zip b/.yarn/cache/@babel-plugin-syntax-flow-npm-7.29.7-d41f3a60ad-3e03792bb2.zip new file mode 100644 index 00000000000..2ff2a5d8e57 Binary files /dev/null and b/.yarn/cache/@babel-plugin-syntax-flow-npm-7.29.7-d41f3a60ad-3e03792bb2.zip differ diff --git a/.yarn/cache/@babel-plugin-syntax-import-assertions-npm-7.29.7-c6fbbb1f1b-a7f24858e7.zip b/.yarn/cache/@babel-plugin-syntax-import-assertions-npm-7.29.7-c6fbbb1f1b-a7f24858e7.zip new file mode 100644 index 00000000000..4f55cca9d1e Binary files /dev/null and b/.yarn/cache/@babel-plugin-syntax-import-assertions-npm-7.29.7-c6fbbb1f1b-a7f24858e7.zip differ diff --git a/.yarn/cache/@babel-plugin-syntax-import-attributes-npm-7.29.7-efe565cbb9-9f47345d09.zip b/.yarn/cache/@babel-plugin-syntax-import-attributes-npm-7.29.7-efe565cbb9-9f47345d09.zip new file mode 100644 index 00000000000..606422c406e Binary files /dev/null and b/.yarn/cache/@babel-plugin-syntax-import-attributes-npm-7.29.7-efe565cbb9-9f47345d09.zip differ diff --git a/.yarn/cache/@babel-plugin-syntax-jsx-npm-7.29.7-887bb0abd4-84150d27c5.zip b/.yarn/cache/@babel-plugin-syntax-jsx-npm-7.29.7-887bb0abd4-84150d27c5.zip new file mode 100644 index 00000000000..15c893deb9b Binary files /dev/null and b/.yarn/cache/@babel-plugin-syntax-jsx-npm-7.29.7-887bb0abd4-84150d27c5.zip differ diff --git a/.yarn/cache/@babel-plugin-syntax-typescript-npm-7.29.7-4784fd3786-ef454d2a7a.zip b/.yarn/cache/@babel-plugin-syntax-typescript-npm-7.29.7-4784fd3786-ef454d2a7a.zip new file mode 100644 index 00000000000..788b914cea1 Binary files /dev/null and b/.yarn/cache/@babel-plugin-syntax-typescript-npm-7.29.7-4784fd3786-ef454d2a7a.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-arrow-functions-npm-7.29.7-1fca2ecac5-0037fd7563.zip b/.yarn/cache/@babel-plugin-transform-arrow-functions-npm-7.29.7-1fca2ecac5-0037fd7563.zip new file mode 100644 index 00000000000..9f4887f4e36 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-arrow-functions-npm-7.29.7-1fca2ecac5-0037fd7563.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-async-generator-functions-npm-7.29.7-515517ba9b-d8239f43b4.zip b/.yarn/cache/@babel-plugin-transform-async-generator-functions-npm-7.29.7-515517ba9b-d8239f43b4.zip new file mode 100644 index 00000000000..1d477af4011 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-async-generator-functions-npm-7.29.7-515517ba9b-d8239f43b4.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-async-to-generator-npm-7.29.7-827a7b6864-e24db9c4c6.zip b/.yarn/cache/@babel-plugin-transform-async-to-generator-npm-7.29.7-827a7b6864-e24db9c4c6.zip new file mode 100644 index 00000000000..caf900ec6f5 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-async-to-generator-npm-7.29.7-827a7b6864-e24db9c4c6.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-block-scoped-functions-npm-7.29.7-c37982cdc3-24f9712ade.zip b/.yarn/cache/@babel-plugin-transform-block-scoped-functions-npm-7.29.7-c37982cdc3-24f9712ade.zip new file mode 100644 index 00000000000..f9dc6ddcb82 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-block-scoped-functions-npm-7.29.7-c37982cdc3-24f9712ade.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-block-scoping-npm-7.29.7-eaca55365a-a17c02f8df.zip b/.yarn/cache/@babel-plugin-transform-block-scoping-npm-7.29.7-eaca55365a-a17c02f8df.zip new file mode 100644 index 00000000000..bf71feb4e97 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-block-scoping-npm-7.29.7-eaca55365a-a17c02f8df.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-class-properties-npm-7.29.7-f4102291f1-0cc5e7a882.zip b/.yarn/cache/@babel-plugin-transform-class-properties-npm-7.29.7-f4102291f1-0cc5e7a882.zip new file mode 100644 index 00000000000..46a12b9b2a7 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-class-properties-npm-7.29.7-f4102291f1-0cc5e7a882.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-class-static-block-npm-7.29.7-1441d89f9a-fe94eb94d8.zip b/.yarn/cache/@babel-plugin-transform-class-static-block-npm-7.29.7-1441d89f9a-fe94eb94d8.zip new file mode 100644 index 00000000000..1b04bd7ae2d Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-class-static-block-npm-7.29.7-1441d89f9a-fe94eb94d8.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-classes-npm-7.29.7-7c007c14af-cc45ff5b5b.zip b/.yarn/cache/@babel-plugin-transform-classes-npm-7.29.7-7c007c14af-cc45ff5b5b.zip new file mode 100644 index 00000000000..ffa38c9786e Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-classes-npm-7.29.7-7c007c14af-cc45ff5b5b.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-computed-properties-npm-7.29.7-04b562814b-ad945a48e6.zip b/.yarn/cache/@babel-plugin-transform-computed-properties-npm-7.29.7-04b562814b-ad945a48e6.zip new file mode 100644 index 00000000000..f8ef753bfdd Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-computed-properties-npm-7.29.7-04b562814b-ad945a48e6.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-destructuring-npm-7.29.7-7d419c193a-5f56c030be.zip b/.yarn/cache/@babel-plugin-transform-destructuring-npm-7.29.7-7d419c193a-5f56c030be.zip new file mode 100644 index 00000000000..4ed11da3edc Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-destructuring-npm-7.29.7-7d419c193a-5f56c030be.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-dotall-regex-npm-7.29.7-fab0bb19ea-537df0fb91.zip b/.yarn/cache/@babel-plugin-transform-dotall-regex-npm-7.29.7-fab0bb19ea-537df0fb91.zip new file mode 100644 index 00000000000..5a98ddef5e4 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-dotall-regex-npm-7.29.7-fab0bb19ea-537df0fb91.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-duplicate-keys-npm-7.29.7-366334e7ee-39bf312a79.zip b/.yarn/cache/@babel-plugin-transform-duplicate-keys-npm-7.29.7-366334e7ee-39bf312a79.zip new file mode 100644 index 00000000000..95e3f524969 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-duplicate-keys-npm-7.29.7-366334e7ee-39bf312a79.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-duplicate-named-capturing-groups-regex-npm-7.29.7-9e10bdb301-fa7fcdbede.zip b/.yarn/cache/@babel-plugin-transform-duplicate-named-capturing-groups-regex-npm-7.29.7-9e10bdb301-fa7fcdbede.zip new file mode 100644 index 00000000000..d41f5617e42 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-duplicate-named-capturing-groups-regex-npm-7.29.7-9e10bdb301-fa7fcdbede.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-dynamic-import-npm-7.29.7-646c91743b-58c035e6b9.zip b/.yarn/cache/@babel-plugin-transform-dynamic-import-npm-7.29.7-646c91743b-58c035e6b9.zip new file mode 100644 index 00000000000..3cf6a8f16d9 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-dynamic-import-npm-7.29.7-646c91743b-58c035e6b9.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-explicit-resource-management-npm-7.29.7-ba23babf60-28ff30f46d.zip b/.yarn/cache/@babel-plugin-transform-explicit-resource-management-npm-7.29.7-ba23babf60-28ff30f46d.zip new file mode 100644 index 00000000000..b0df885e2b9 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-explicit-resource-management-npm-7.29.7-ba23babf60-28ff30f46d.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-exponentiation-operator-npm-7.29.7-b027e388aa-bf0366d77d.zip b/.yarn/cache/@babel-plugin-transform-exponentiation-operator-npm-7.29.7-b027e388aa-bf0366d77d.zip new file mode 100644 index 00000000000..fe8385a6b2c Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-exponentiation-operator-npm-7.29.7-b027e388aa-bf0366d77d.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-export-namespace-from-npm-7.29.7-063a6b0922-d157d62b14.zip b/.yarn/cache/@babel-plugin-transform-export-namespace-from-npm-7.29.7-063a6b0922-d157d62b14.zip new file mode 100644 index 00000000000..b237a24cd47 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-export-namespace-from-npm-7.29.7-063a6b0922-d157d62b14.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-flow-strip-types-npm-7.29.7-7d249e90ed-bc6e94f539.zip b/.yarn/cache/@babel-plugin-transform-flow-strip-types-npm-7.29.7-7d249e90ed-bc6e94f539.zip new file mode 100644 index 00000000000..fdd464f928c Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-flow-strip-types-npm-7.29.7-7d249e90ed-bc6e94f539.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-for-of-npm-7.29.7-018cc07c68-7641d5eb4e.zip b/.yarn/cache/@babel-plugin-transform-for-of-npm-7.29.7-018cc07c68-7641d5eb4e.zip new file mode 100644 index 00000000000..2d905a15511 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-for-of-npm-7.29.7-018cc07c68-7641d5eb4e.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-function-name-npm-7.29.7-f615ee530a-87a6329442.zip b/.yarn/cache/@babel-plugin-transform-function-name-npm-7.29.7-f615ee530a-87a6329442.zip new file mode 100644 index 00000000000..44e4bdc8b4f Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-function-name-npm-7.29.7-f615ee530a-87a6329442.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-json-strings-npm-7.29.7-316c18256c-3af97e144e.zip b/.yarn/cache/@babel-plugin-transform-json-strings-npm-7.29.7-316c18256c-3af97e144e.zip new file mode 100644 index 00000000000..7e752bc22e9 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-json-strings-npm-7.29.7-316c18256c-3af97e144e.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-literals-npm-7.29.7-8498d15ac3-aadb2b3fe8.zip b/.yarn/cache/@babel-plugin-transform-literals-npm-7.29.7-8498d15ac3-aadb2b3fe8.zip new file mode 100644 index 00000000000..f5c3ee49b7e Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-literals-npm-7.29.7-8498d15ac3-aadb2b3fe8.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-logical-assignment-operators-npm-7.29.7-48eea3f2bb-374d83dfbb.zip b/.yarn/cache/@babel-plugin-transform-logical-assignment-operators-npm-7.29.7-48eea3f2bb-374d83dfbb.zip new file mode 100644 index 00000000000..7f4d54acee1 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-logical-assignment-operators-npm-7.29.7-48eea3f2bb-374d83dfbb.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-member-expression-literals-npm-7.29.7-25e7a7acc8-698cbc9500.zip b/.yarn/cache/@babel-plugin-transform-member-expression-literals-npm-7.29.7-25e7a7acc8-698cbc9500.zip new file mode 100644 index 00000000000..10580cafcea Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-member-expression-literals-npm-7.29.7-25e7a7acc8-698cbc9500.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-modules-amd-npm-7.29.7-2231f3ab5a-6fce7d3292.zip b/.yarn/cache/@babel-plugin-transform-modules-amd-npm-7.29.7-2231f3ab5a-6fce7d3292.zip new file mode 100644 index 00000000000..e420cb9519c Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-modules-amd-npm-7.29.7-2231f3ab5a-6fce7d3292.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-modules-commonjs-npm-7.29.7-4e669a8fff-e9d8102dec.zip b/.yarn/cache/@babel-plugin-transform-modules-commonjs-npm-7.29.7-4e669a8fff-e9d8102dec.zip new file mode 100644 index 00000000000..d0749a5d4c5 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-modules-commonjs-npm-7.29.7-4e669a8fff-e9d8102dec.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-modules-systemjs-npm-7.29.7-28b1ebcdb0-185d26d1f2.zip b/.yarn/cache/@babel-plugin-transform-modules-systemjs-npm-7.29.7-28b1ebcdb0-185d26d1f2.zip new file mode 100644 index 00000000000..a8eeb15e13e Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-modules-systemjs-npm-7.29.7-28b1ebcdb0-185d26d1f2.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-modules-umd-npm-7.29.7-7c76a1f659-589f5c30a9.zip b/.yarn/cache/@babel-plugin-transform-modules-umd-npm-7.29.7-7c76a1f659-589f5c30a9.zip new file mode 100644 index 00000000000..fae34a5dcf0 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-modules-umd-npm-7.29.7-7c76a1f659-589f5c30a9.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-named-capturing-groups-regex-npm-7.29.7-b4aa8fa023-3a481be133.zip b/.yarn/cache/@babel-plugin-transform-named-capturing-groups-regex-npm-7.29.7-b4aa8fa023-3a481be133.zip new file mode 100644 index 00000000000..b3e48007b63 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-named-capturing-groups-regex-npm-7.29.7-b4aa8fa023-3a481be133.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-new-target-npm-7.29.7-839e5bae26-35b4c29534.zip b/.yarn/cache/@babel-plugin-transform-new-target-npm-7.29.7-839e5bae26-35b4c29534.zip new file mode 100644 index 00000000000..065eb40e8a4 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-new-target-npm-7.29.7-839e5bae26-35b4c29534.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-nullish-coalescing-operator-npm-7.29.7-1ea8485d4f-f486e737dd.zip b/.yarn/cache/@babel-plugin-transform-nullish-coalescing-operator-npm-7.29.7-1ea8485d4f-f486e737dd.zip new file mode 100644 index 00000000000..e1bfee15666 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-nullish-coalescing-operator-npm-7.29.7-1ea8485d4f-f486e737dd.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-numeric-separator-npm-7.29.7-f62950bdfc-6177df9e1a.zip b/.yarn/cache/@babel-plugin-transform-numeric-separator-npm-7.29.7-f62950bdfc-6177df9e1a.zip new file mode 100644 index 00000000000..7d003beeebe Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-numeric-separator-npm-7.29.7-f62950bdfc-6177df9e1a.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-object-rest-spread-npm-7.29.7-fde8b1d70e-e09bcc8800.zip b/.yarn/cache/@babel-plugin-transform-object-rest-spread-npm-7.29.7-fde8b1d70e-e09bcc8800.zip new file mode 100644 index 00000000000..3034e592bfa Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-object-rest-spread-npm-7.29.7-fde8b1d70e-e09bcc8800.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-object-super-npm-7.29.7-94aea6af96-65ed871956.zip b/.yarn/cache/@babel-plugin-transform-object-super-npm-7.29.7-94aea6af96-65ed871956.zip new file mode 100644 index 00000000000..262e4e4e06e Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-object-super-npm-7.29.7-94aea6af96-65ed871956.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-optional-catch-binding-npm-7.29.7-0fd199b1b5-4b6e41e1dc.zip b/.yarn/cache/@babel-plugin-transform-optional-catch-binding-npm-7.29.7-0fd199b1b5-4b6e41e1dc.zip new file mode 100644 index 00000000000..ad4d65f1581 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-optional-catch-binding-npm-7.29.7-0fd199b1b5-4b6e41e1dc.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-optional-chaining-npm-7.29.7-968c69098f-6255d259bb.zip b/.yarn/cache/@babel-plugin-transform-optional-chaining-npm-7.29.7-968c69098f-6255d259bb.zip new file mode 100644 index 00000000000..29c3b988ec0 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-optional-chaining-npm-7.29.7-968c69098f-6255d259bb.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-parameters-npm-7.29.7-782ac94bf3-615cdd72dc.zip b/.yarn/cache/@babel-plugin-transform-parameters-npm-7.29.7-782ac94bf3-615cdd72dc.zip new file mode 100644 index 00000000000..2c28c7d1714 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-parameters-npm-7.29.7-782ac94bf3-615cdd72dc.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-private-methods-npm-7.29.7-a97d685cc4-5055af2b86.zip b/.yarn/cache/@babel-plugin-transform-private-methods-npm-7.29.7-a97d685cc4-5055af2b86.zip new file mode 100644 index 00000000000..edb44ee9d42 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-private-methods-npm-7.29.7-a97d685cc4-5055af2b86.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-private-property-in-object-npm-7.29.7-2072164ecf-068ff9e35e.zip b/.yarn/cache/@babel-plugin-transform-private-property-in-object-npm-7.29.7-2072164ecf-068ff9e35e.zip new file mode 100644 index 00000000000..d150bf327e3 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-private-property-in-object-npm-7.29.7-2072164ecf-068ff9e35e.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-property-literals-npm-7.29.7-a6ae518e94-7e7a557df8.zip b/.yarn/cache/@babel-plugin-transform-property-literals-npm-7.29.7-a6ae518e94-7e7a557df8.zip new file mode 100644 index 00000000000..7bd62f147fe Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-property-literals-npm-7.29.7-a6ae518e94-7e7a557df8.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-react-display-name-npm-7.29.7-e5a79de884-ded95cce18.zip b/.yarn/cache/@babel-plugin-transform-react-display-name-npm-7.29.7-e5a79de884-ded95cce18.zip new file mode 100644 index 00000000000..84cdd6be4e8 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-react-display-name-npm-7.29.7-e5a79de884-ded95cce18.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-react-jsx-development-npm-7.29.7-a6ca3acfbf-c535bb5ee0.zip b/.yarn/cache/@babel-plugin-transform-react-jsx-development-npm-7.29.7-a6ca3acfbf-c535bb5ee0.zip new file mode 100644 index 00000000000..2880cc29378 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-react-jsx-development-npm-7.29.7-a6ca3acfbf-c535bb5ee0.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-react-jsx-npm-7.29.7-b5550a3619-d50e5d6f12.zip b/.yarn/cache/@babel-plugin-transform-react-jsx-npm-7.29.7-b5550a3619-d50e5d6f12.zip new file mode 100644 index 00000000000..0ada155e9c5 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-react-jsx-npm-7.29.7-b5550a3619-d50e5d6f12.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-react-pure-annotations-npm-7.29.7-ffad7e39da-7b6bc9e9db.zip b/.yarn/cache/@babel-plugin-transform-react-pure-annotations-npm-7.29.7-ffad7e39da-7b6bc9e9db.zip new file mode 100644 index 00000000000..19e98ca7b29 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-react-pure-annotations-npm-7.29.7-ffad7e39da-7b6bc9e9db.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-regenerator-npm-7.29.7-91655863a3-1a136712ba.zip b/.yarn/cache/@babel-plugin-transform-regenerator-npm-7.29.7-91655863a3-1a136712ba.zip new file mode 100644 index 00000000000..88716f50246 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-regenerator-npm-7.29.7-91655863a3-1a136712ba.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-regexp-modifiers-npm-7.29.7-60ce41298b-bfbc6b898a.zip b/.yarn/cache/@babel-plugin-transform-regexp-modifiers-npm-7.29.7-60ce41298b-bfbc6b898a.zip new file mode 100644 index 00000000000..153429ae3db Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-regexp-modifiers-npm-7.29.7-60ce41298b-bfbc6b898a.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-reserved-words-npm-7.29.7-9b7ce11936-ffd7f86ddc.zip b/.yarn/cache/@babel-plugin-transform-reserved-words-npm-7.29.7-9b7ce11936-ffd7f86ddc.zip new file mode 100644 index 00000000000..603d65c6f26 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-reserved-words-npm-7.29.7-9b7ce11936-ffd7f86ddc.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-shorthand-properties-npm-7.29.7-4d6f6f9e1b-c57ef27853.zip b/.yarn/cache/@babel-plugin-transform-shorthand-properties-npm-7.29.7-4d6f6f9e1b-c57ef27853.zip new file mode 100644 index 00000000000..8c7cb4520f5 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-shorthand-properties-npm-7.29.7-4d6f6f9e1b-c57ef27853.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-spread-npm-7.29.7-534950e479-eb25f24d9a.zip b/.yarn/cache/@babel-plugin-transform-spread-npm-7.29.7-534950e479-eb25f24d9a.zip new file mode 100644 index 00000000000..3b95c9853eb Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-spread-npm-7.29.7-534950e479-eb25f24d9a.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-sticky-regex-npm-7.29.7-e6d3a5ff8c-16b570c027.zip b/.yarn/cache/@babel-plugin-transform-sticky-regex-npm-7.29.7-e6d3a5ff8c-16b570c027.zip new file mode 100644 index 00000000000..2dc1cc59bb1 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-sticky-regex-npm-7.29.7-e6d3a5ff8c-16b570c027.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-template-literals-npm-7.29.7-3e0e7eca36-d1014dab02.zip b/.yarn/cache/@babel-plugin-transform-template-literals-npm-7.29.7-3e0e7eca36-d1014dab02.zip new file mode 100644 index 00000000000..b750241da28 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-template-literals-npm-7.29.7-3e0e7eca36-d1014dab02.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-typeof-symbol-npm-7.29.7-b1ac94cd5d-90c2308f97.zip b/.yarn/cache/@babel-plugin-transform-typeof-symbol-npm-7.29.7-b1ac94cd5d-90c2308f97.zip new file mode 100644 index 00000000000..53212dd5e45 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-typeof-symbol-npm-7.29.7-b1ac94cd5d-90c2308f97.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-typescript-npm-7.29.7-2404b035ea-e95bce53fa.zip b/.yarn/cache/@babel-plugin-transform-typescript-npm-7.29.7-2404b035ea-e95bce53fa.zip new file mode 100644 index 00000000000..f86c47bcb97 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-typescript-npm-7.29.7-2404b035ea-e95bce53fa.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-unicode-escapes-npm-7.29.7-4dad82fc78-cf337bf93a.zip b/.yarn/cache/@babel-plugin-transform-unicode-escapes-npm-7.29.7-4dad82fc78-cf337bf93a.zip new file mode 100644 index 00000000000..287685b4449 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-unicode-escapes-npm-7.29.7-4dad82fc78-cf337bf93a.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-unicode-property-regex-npm-7.29.7-9914cc976c-03ee0b5d27.zip b/.yarn/cache/@babel-plugin-transform-unicode-property-regex-npm-7.29.7-9914cc976c-03ee0b5d27.zip new file mode 100644 index 00000000000..a751b2ced3e Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-unicode-property-regex-npm-7.29.7-9914cc976c-03ee0b5d27.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-unicode-regex-npm-7.29.7-e5cfc255ce-1ade0672ae.zip b/.yarn/cache/@babel-plugin-transform-unicode-regex-npm-7.29.7-e5cfc255ce-1ade0672ae.zip new file mode 100644 index 00000000000..e8be1f9b363 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-unicode-regex-npm-7.29.7-e5cfc255ce-1ade0672ae.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-unicode-sets-regex-npm-7.29.7-4c2f1f220e-680c22e2a6.zip b/.yarn/cache/@babel-plugin-transform-unicode-sets-regex-npm-7.29.7-4c2f1f220e-680c22e2a6.zip new file mode 100644 index 00000000000..a5dfaaa8bf4 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-unicode-sets-regex-npm-7.29.7-4c2f1f220e-680c22e2a6.zip differ diff --git a/.yarn/cache/@babel-preset-env-npm-7.29.7-03ad83e12d-36deae2ea4.zip b/.yarn/cache/@babel-preset-env-npm-7.29.7-03ad83e12d-36deae2ea4.zip new file mode 100644 index 00000000000..d217023f15f Binary files /dev/null and b/.yarn/cache/@babel-preset-env-npm-7.29.7-03ad83e12d-36deae2ea4.zip differ diff --git a/.yarn/cache/@babel-preset-flow-npm-7.29.7-4e249acd3e-562fe8494d.zip b/.yarn/cache/@babel-preset-flow-npm-7.29.7-4e249acd3e-562fe8494d.zip new file mode 100644 index 00000000000..d299be09076 Binary files /dev/null and b/.yarn/cache/@babel-preset-flow-npm-7.29.7-4e249acd3e-562fe8494d.zip differ diff --git a/.yarn/cache/@babel-preset-modules-npm-0.1.6-no-external-plugins-0ae0b52ff3-4855e799bc.zip b/.yarn/cache/@babel-preset-modules-npm-0.1.6-no-external-plugins-0ae0b52ff3-4855e799bc.zip new file mode 100644 index 00000000000..8dd341b9dda Binary files /dev/null and b/.yarn/cache/@babel-preset-modules-npm-0.1.6-no-external-plugins-0ae0b52ff3-4855e799bc.zip differ diff --git a/.yarn/cache/@babel-preset-react-npm-7.29.7-63f809c996-ec9d4d418d.zip b/.yarn/cache/@babel-preset-react-npm-7.29.7-63f809c996-ec9d4d418d.zip new file mode 100644 index 00000000000..652e83fcb71 Binary files /dev/null and b/.yarn/cache/@babel-preset-react-npm-7.29.7-63f809c996-ec9d4d418d.zip differ diff --git a/.yarn/cache/@babel-preset-typescript-npm-7.29.7-2dbc1e1fa1-f2f58cbbbd.zip b/.yarn/cache/@babel-preset-typescript-npm-7.29.7-2dbc1e1fa1-f2f58cbbbd.zip new file mode 100644 index 00000000000..5a08e3acde0 Binary files /dev/null and b/.yarn/cache/@babel-preset-typescript-npm-7.29.7-2dbc1e1fa1-f2f58cbbbd.zip differ diff --git a/.yarn/cache/@babel-runtime-npm-7.29.7-423e8cd4b6-bc311855c6.zip b/.yarn/cache/@babel-runtime-npm-7.29.7-423e8cd4b6-bc311855c6.zip new file mode 100644 index 00000000000..fad9917dd73 Binary files /dev/null and b/.yarn/cache/@babel-runtime-npm-7.29.7-423e8cd4b6-bc311855c6.zip differ diff --git a/.yarn/cache/@babel-template-npm-7.29.7-46b79049c7-521eb6a1fd.zip b/.yarn/cache/@babel-template-npm-7.29.7-46b79049c7-521eb6a1fd.zip new file mode 100644 index 00000000000..9322dfc2833 Binary files /dev/null and b/.yarn/cache/@babel-template-npm-7.29.7-46b79049c7-521eb6a1fd.zip differ diff --git a/.yarn/cache/@babel-traverse-npm-7.29.7-3d605855b6-6c4508fd2a.zip b/.yarn/cache/@babel-traverse-npm-7.29.7-3d605855b6-6c4508fd2a.zip new file mode 100644 index 00000000000..fe7ceef5567 Binary files /dev/null and b/.yarn/cache/@babel-traverse-npm-7.29.7-3d605855b6-6c4508fd2a.zip differ diff --git a/.yarn/cache/@babel-types-npm-7.29.7-8e5b8d613f-71c46837d2.zip b/.yarn/cache/@babel-types-npm-7.29.7-8e5b8d613f-71c46837d2.zip new file mode 100644 index 00000000000..fd5dba4cd83 Binary files /dev/null and b/.yarn/cache/@babel-types-npm-7.29.7-8e5b8d613f-71c46837d2.zip differ diff --git a/.yarn/cache/@hapi-bourne-npm-3.0.0-9b2a238f08-7174cab6c3.zip b/.yarn/cache/@hapi-bourne-npm-3.0.0-9b2a238f08-7174cab6c3.zip new file mode 100644 index 00000000000..830d75f74ca Binary files /dev/null and b/.yarn/cache/@hapi-bourne-npm-3.0.0-9b2a238f08-7174cab6c3.zip differ diff --git a/.yarn/cache/@jridgewell-gen-mapping-npm-0.3.13-9bd96ac800-f2105acefc.zip b/.yarn/cache/@jridgewell-gen-mapping-npm-0.3.13-9bd96ac800-f2105acefc.zip new file mode 100644 index 00000000000..2615e430124 Binary files /dev/null and b/.yarn/cache/@jridgewell-gen-mapping-npm-0.3.13-9bd96ac800-f2105acefc.zip differ diff --git a/.yarn/cache/@jridgewell-remapping-npm-2.3.5-df8dacc063-4a66a7397c.zip b/.yarn/cache/@jridgewell-remapping-npm-2.3.5-df8dacc063-4a66a7397c.zip new file mode 100644 index 00000000000..816744cdd99 Binary files /dev/null and b/.yarn/cache/@jridgewell-remapping-npm-2.3.5-df8dacc063-4a66a7397c.zip differ diff --git a/.yarn/cache/@jridgewell-sourcemap-codec-npm-1.5.5-5189d9fc79-c2e36e6797.zip b/.yarn/cache/@jridgewell-sourcemap-codec-npm-1.5.5-5189d9fc79-c2e36e6797.zip new file mode 100644 index 00000000000..49cffdd42b2 Binary files /dev/null and b/.yarn/cache/@jridgewell-sourcemap-codec-npm-1.5.5-5189d9fc79-c2e36e6797.zip differ diff --git a/.yarn/cache/@jridgewell-trace-mapping-npm-0.3.31-1ae81d75ac-af8fda2431.zip b/.yarn/cache/@jridgewell-trace-mapping-npm-0.3.31-1ae81d75ac-af8fda2431.zip new file mode 100644 index 00000000000..1d292a704ca Binary files /dev/null and b/.yarn/cache/@jridgewell-trace-mapping-npm-0.3.31-1ae81d75ac-af8fda2431.zip differ diff --git a/.yarn/cache/@paralleldrive-cuid2-npm-2.3.1-34889f1c27-1310abcdf8.zip b/.yarn/cache/@paralleldrive-cuid2-npm-2.3.1-34889f1c27-1310abcdf8.zip new file mode 100644 index 00000000000..77b2db0a0d2 Binary files /dev/null and b/.yarn/cache/@paralleldrive-cuid2-npm-2.3.1-34889f1c27-1310abcdf8.zip differ diff --git a/.yarn/cache/@sveltejs-acorn-typescript-npm-1.0.11-7004341db8-b2f2526290.zip b/.yarn/cache/@sveltejs-acorn-typescript-npm-1.0.11-7004341db8-b2f2526290.zip new file mode 100644 index 00000000000..1afddfab7df Binary files /dev/null and b/.yarn/cache/@sveltejs-acorn-typescript-npm-1.0.11-7004341db8-b2f2526290.zip differ diff --git a/.yarn/cache/@types-accepts-npm-1.3.7-96df7c6899-7678cf7497.zip b/.yarn/cache/@types-accepts-npm-1.3.7-96df7c6899-7678cf7497.zip new file mode 100644 index 00000000000..27fa22745d3 Binary files /dev/null and b/.yarn/cache/@types-accepts-npm-1.3.7-96df7c6899-7678cf7497.zip differ diff --git a/.yarn/cache/@types-co-body-npm-6.1.3-187348a50c-e93fdc177f.zip b/.yarn/cache/@types-co-body-npm-6.1.3-187348a50c-e93fdc177f.zip new file mode 100644 index 00000000000..e2951ea2631 Binary files /dev/null and b/.yarn/cache/@types-co-body-npm-6.1.3-187348a50c-e93fdc177f.zip differ diff --git a/.yarn/cache/@types-content-disposition-npm-0.5.9-0a4389ae4e-d895703c00.zip b/.yarn/cache/@types-content-disposition-npm-0.5.9-0a4389ae4e-d895703c00.zip new file mode 100644 index 00000000000..0a7b8655f27 Binary files /dev/null and b/.yarn/cache/@types-content-disposition-npm-0.5.9-0a4389ae4e-d895703c00.zip differ diff --git a/.yarn/cache/@types-cookies-npm-0.9.2-a53eed6bb5-12997c120d.zip b/.yarn/cache/@types-cookies-npm-0.9.2-a53eed6bb5-12997c120d.zip new file mode 100644 index 00000000000..d90a51886e3 Binary files /dev/null and b/.yarn/cache/@types-cookies-npm-0.9.2-a53eed6bb5-12997c120d.zip differ diff --git a/.yarn/cache/@types-estree-npm-1.0.9-63428f58ff-752c0afee3.zip b/.yarn/cache/@types-estree-npm-1.0.9-63428f58ff-752c0afee3.zip new file mode 100644 index 00000000000..9f5840e1518 Binary files /dev/null and b/.yarn/cache/@types-estree-npm-1.0.9-63428f58ff-752c0afee3.zip differ diff --git a/.yarn/cache/@types-formidable-npm-3.5.1-c347b639cb-4f9599849a.zip b/.yarn/cache/@types-formidable-npm-3.5.1-c347b639cb-4f9599849a.zip new file mode 100644 index 00000000000..fd9d232fb9d Binary files /dev/null and b/.yarn/cache/@types-formidable-npm-3.5.1-c347b639cb-4f9599849a.zip differ diff --git a/.yarn/cache/@types-http-assert-npm-1.5.6-c3bc41fbf7-dfe1010164.zip b/.yarn/cache/@types-http-assert-npm-1.5.6-c3bc41fbf7-dfe1010164.zip new file mode 100644 index 00000000000..5b536309f2e Binary files /dev/null and b/.yarn/cache/@types-http-assert-npm-1.5.6-c3bc41fbf7-dfe1010164.zip differ diff --git a/.yarn/cache/@types-http-errors-npm-2.0.5-fc57abf6db-a88da66936.zip b/.yarn/cache/@types-http-errors-npm-2.0.5-fc57abf6db-a88da66936.zip new file mode 100644 index 00000000000..58286723382 Binary files /dev/null and b/.yarn/cache/@types-http-errors-npm-2.0.5-fc57abf6db-a88da66936.zip differ diff --git a/.yarn/cache/@types-keygrip-npm-1.0.6-25e224891d-d157f60bf9.zip b/.yarn/cache/@types-keygrip-npm-1.0.6-25e224891d-d157f60bf9.zip new file mode 100644 index 00000000000..5878993d6f9 Binary files /dev/null and b/.yarn/cache/@types-keygrip-npm-1.0.6-25e224891d-d157f60bf9.zip differ diff --git a/.yarn/cache/@types-koa-compose-npm-3.2.9-9d1fbb9f04-0f86016fc8.zip b/.yarn/cache/@types-koa-compose-npm-3.2.9-9d1fbb9f04-0f86016fc8.zip new file mode 100644 index 00000000000..a94ab71df93 Binary files /dev/null and b/.yarn/cache/@types-koa-compose-npm-3.2.9-9d1fbb9f04-0f86016fc8.zip differ diff --git a/.yarn/cache/@types-koa-npm-3.0.3-a63087758e-31d36837e9.zip b/.yarn/cache/@types-koa-npm-3.0.3-a63087758e-31d36837e9.zip new file mode 100644 index 00000000000..cd5ebae39b3 Binary files /dev/null and b/.yarn/cache/@types-koa-npm-3.0.3-a63087758e-31d36837e9.zip differ diff --git a/.yarn/cache/@types-trusted-types-npm-2.0.7-a07fc44f59-8e4202766a.zip b/.yarn/cache/@types-trusted-types-npm-2.0.7-a07fc44f59-8e4202766a.zip new file mode 100644 index 00000000000..3d2f216ed3b Binary files /dev/null and b/.yarn/cache/@types-trusted-types-npm-2.0.7-a07fc44f59-8e4202766a.zip differ diff --git a/.yarn/cache/acorn-npm-8.17.0-c53f71d3b1-98f0800a48.zip b/.yarn/cache/acorn-npm-8.17.0-c53f71d3b1-98f0800a48.zip new file mode 100644 index 00000000000..4e46700347b Binary files /dev/null and b/.yarn/cache/acorn-npm-8.17.0-c53f71d3b1-98f0800a48.zip differ diff --git a/.yarn/cache/ajv-npm-6.12.3-aaadf00f0f-ca559d3471.zip b/.yarn/cache/ajv-npm-6.12.3-aaadf00f0f-ca559d3471.zip new file mode 100644 index 00000000000..96611cf051a Binary files /dev/null and b/.yarn/cache/ajv-npm-6.12.3-aaadf00f0f-ca559d3471.zip differ diff --git a/.yarn/cache/ansi-regex-npm-2.1.1-ddd24d102b-190abd03e4.zip b/.yarn/cache/ansi-regex-npm-2.1.1-ddd24d102b-190abd03e4.zip new file mode 100644 index 00000000000..39b46403778 Binary files /dev/null and b/.yarn/cache/ansi-regex-npm-2.1.1-ddd24d102b-190abd03e4.zip differ diff --git a/.yarn/cache/ansi-styles-npm-2.2.1-f3297e782c-ebc0e00381.zip b/.yarn/cache/ansi-styles-npm-2.2.1-f3297e782c-ebc0e00381.zip new file mode 100644 index 00000000000..5581240ca2b Binary files /dev/null and b/.yarn/cache/ansi-styles-npm-2.2.1-f3297e782c-ebc0e00381.zip differ diff --git a/.yarn/cache/aria-query-npm-5.3.1-fa607704a3-8f7ece335e.zip b/.yarn/cache/aria-query-npm-5.3.1-fa607704a3-8f7ece335e.zip new file mode 100644 index 00000000000..e899bd4390e Binary files /dev/null and b/.yarn/cache/aria-query-npm-5.3.1-fa607704a3-8f7ece335e.zip differ diff --git a/.yarn/cache/async-function-npm-1.0.0-a81667ebcd-9102e246d1.zip b/.yarn/cache/async-function-npm-1.0.0-a81667ebcd-9102e246d1.zip new file mode 100644 index 00000000000..09de89ffe03 Binary files /dev/null and b/.yarn/cache/async-function-npm-1.0.0-a81667ebcd-9102e246d1.zip differ diff --git a/.yarn/cache/async-generator-function-npm-1.0.0-14cf981d13-74a71a4a2d.zip b/.yarn/cache/async-generator-function-npm-1.0.0-14cf981d13-74a71a4a2d.zip new file mode 100644 index 00000000000..575a5c3bcdb Binary files /dev/null and b/.yarn/cache/async-generator-function-npm-1.0.0-14cf981d13-74a71a4a2d.zip differ diff --git a/.yarn/cache/axobject-query-npm-4.1.0-9703554323-7d1e87bf0a.zip b/.yarn/cache/axobject-query-npm-4.1.0-9703554323-7d1e87bf0a.zip new file mode 100644 index 00000000000..1d65144cce3 Binary files /dev/null and b/.yarn/cache/axobject-query-npm-4.1.0-9703554323-7d1e87bf0a.zip differ diff --git a/.yarn/cache/babel-plugin-macros-npm-2.8.0-451367d7e7-59b09a21cf.zip b/.yarn/cache/babel-plugin-macros-npm-2.8.0-451367d7e7-59b09a21cf.zip new file mode 100644 index 00000000000..cdb42c1baf2 Binary files /dev/null and b/.yarn/cache/babel-plugin-macros-npm-2.8.0-451367d7e7-59b09a21cf.zip differ diff --git a/.yarn/cache/babel-plugin-polyfill-corejs2-npm-0.4.17-0f25e0dfad-945f80f413.zip b/.yarn/cache/babel-plugin-polyfill-corejs2-npm-0.4.17-0f25e0dfad-945f80f413.zip new file mode 100644 index 00000000000..0b3ad7ef9e6 Binary files /dev/null and b/.yarn/cache/babel-plugin-polyfill-corejs2-npm-0.4.17-0f25e0dfad-945f80f413.zip differ diff --git a/.yarn/cache/babel-plugin-polyfill-corejs3-npm-0.14.2-a37e45ac92-4bcaf4da65.zip b/.yarn/cache/babel-plugin-polyfill-corejs3-npm-0.14.2-a37e45ac92-4bcaf4da65.zip new file mode 100644 index 00000000000..e7a61e41cb3 Binary files /dev/null and b/.yarn/cache/babel-plugin-polyfill-corejs3-npm-0.14.2-a37e45ac92-4bcaf4da65.zip differ diff --git a/.yarn/cache/babel-plugin-polyfill-regenerator-npm-0.6.8-59675073c3-974464353d.zip b/.yarn/cache/babel-plugin-polyfill-regenerator-npm-0.6.8-59675073c3-974464353d.zip new file mode 100644 index 00000000000..4c49a640280 Binary files /dev/null and b/.yarn/cache/babel-plugin-polyfill-regenerator-npm-0.6.8-59675073c3-974464353d.zip differ diff --git a/.yarn/cache/babel-plugin-ttag-npm-1.8.16-b53ce566f7-cf69ead251.zip b/.yarn/cache/babel-plugin-ttag-npm-1.8.16-b53ce566f7-cf69ead251.zip new file mode 100644 index 00000000000..ef44563102c Binary files /dev/null and b/.yarn/cache/babel-plugin-ttag-npm-1.8.16-b53ce566f7-cf69ead251.zip differ diff --git a/.yarn/cache/baseline-browser-mapping-npm-2.11.3-1b065b48f1-3599333539.zip b/.yarn/cache/baseline-browser-mapping-npm-2.11.3-1b065b48f1-3599333539.zip new file mode 100644 index 00000000000..95827150033 Binary files /dev/null and b/.yarn/cache/baseline-browser-mapping-npm-2.11.3-1b065b48f1-3599333539.zip differ diff --git a/.yarn/cache/browserslist-npm-4.28.7-844ec494a5-81093d27f0.zip b/.yarn/cache/browserslist-npm-4.28.7-844ec494a5-81093d27f0.zip new file mode 100644 index 00000000000..54ffcaff782 Binary files /dev/null and b/.yarn/cache/browserslist-npm-4.28.7-844ec494a5-81093d27f0.zip differ diff --git a/.yarn/cache/cache-content-type-npm-1.0.1-f709f8c309-18db4d5945.zip b/.yarn/cache/cache-content-type-npm-1.0.1-f709f8c309-18db4d5945.zip new file mode 100644 index 00000000000..a3422158198 Binary files /dev/null and b/.yarn/cache/cache-content-type-npm-1.0.1-f709f8c309-18db4d5945.zip differ diff --git a/.yarn/cache/call-bind-apply-helpers-npm-1.0.2-3eedbea3bb-b2863d74fc.zip b/.yarn/cache/call-bind-apply-helpers-npm-1.0.2-3eedbea3bb-b2863d74fc.zip new file mode 100644 index 00000000000..4f131767e74 Binary files /dev/null and b/.yarn/cache/call-bind-apply-helpers-npm-1.0.2-3eedbea3bb-b2863d74fc.zip differ diff --git a/.yarn/cache/call-bound-npm-1.0.4-359cfa32c7-2f6399488d.zip b/.yarn/cache/call-bound-npm-1.0.4-359cfa32c7-2f6399488d.zip new file mode 100644 index 00000000000..961643ea063 Binary files /dev/null and b/.yarn/cache/call-bound-npm-1.0.4-359cfa32c7-2f6399488d.zip differ diff --git a/.yarn/cache/caniuse-lite-npm-1.0.30001806-92c0bb0a20-4b4a970fbd.zip b/.yarn/cache/caniuse-lite-npm-1.0.30001806-92c0bb0a20-4b4a970fbd.zip new file mode 100644 index 00000000000..8e3a1347ca7 Binary files /dev/null and b/.yarn/cache/caniuse-lite-npm-1.0.30001806-92c0bb0a20-4b4a970fbd.zip differ diff --git a/.yarn/cache/chalk-npm-1.1.3-59144c3a87-9d2ea6b98f.zip b/.yarn/cache/chalk-npm-1.1.3-59144c3a87-9d2ea6b98f.zip new file mode 100644 index 00000000000..e7d3003b97d Binary files /dev/null and b/.yarn/cache/chalk-npm-1.1.3-59144c3a87-9d2ea6b98f.zip differ diff --git a/.yarn/cache/cli-cursor-npm-2.1.0-3920629c9c-d88e97bfda.zip b/.yarn/cache/cli-cursor-npm-2.1.0-3920629c9c-d88e97bfda.zip new file mode 100644 index 00000000000..b8aff0b4656 Binary files /dev/null and b/.yarn/cache/cli-cursor-npm-2.1.0-3920629c9c-d88e97bfda.zip differ diff --git a/.yarn/cache/cli-spinners-npm-1.3.1-591ebb35f1-4f95fd69a2.zip b/.yarn/cache/cli-spinners-npm-1.3.1-591ebb35f1-4f95fd69a2.zip new file mode 100644 index 00000000000..2c3dc3cf839 Binary files /dev/null and b/.yarn/cache/cli-spinners-npm-1.3.1-591ebb35f1-4f95fd69a2.zip differ diff --git a/.yarn/cache/clsx-npm-2.1.1-96125b98be-acd3e1ab9d.zip b/.yarn/cache/clsx-npm-2.1.1-96125b98be-acd3e1ab9d.zip new file mode 100644 index 00000000000..3110260cf4a Binary files /dev/null and b/.yarn/cache/clsx-npm-2.1.1-96125b98be-acd3e1ab9d.zip differ diff --git a/.yarn/cache/co-body-npm-6.2.0-84e35e7662-c89336086b.zip b/.yarn/cache/co-body-npm-6.2.0-84e35e7662-c89336086b.zip new file mode 100644 index 00000000000..1ea6406d937 Binary files /dev/null and b/.yarn/cache/co-body-npm-6.2.0-84e35e7662-c89336086b.zip differ diff --git a/.yarn/cache/cookies-npm-0.9.1-80a82ae099-213e4d1484.zip b/.yarn/cache/cookies-npm-0.9.1-80a82ae099-213e4d1484.zip new file mode 100644 index 00000000000..8701554576a Binary files /dev/null and b/.yarn/cache/cookies-npm-0.9.1-80a82ae099-213e4d1484.zip differ diff --git a/.yarn/cache/core-js-compat-npm-3.49.0-7124aa5467-21afa75a64.zip b/.yarn/cache/core-js-compat-npm-3.49.0-7124aa5467-21afa75a64.zip new file mode 100644 index 00000000000..8063fc82e86 Binary files /dev/null and b/.yarn/cache/core-js-compat-npm-3.49.0-7124aa5467-21afa75a64.zip differ diff --git a/.yarn/cache/cosmiconfig-npm-6.0.0-cb7d64a2b9-8eed7c854b.zip b/.yarn/cache/cosmiconfig-npm-6.0.0-cb7d64a2b9-8eed7c854b.zip new file mode 100644 index 00000000000..3e83d75a278 Binary files /dev/null and b/.yarn/cache/cosmiconfig-npm-6.0.0-cb7d64a2b9-8eed7c854b.zip differ diff --git a/.yarn/cache/deep-equal-npm-1.0.1-f05565c4e5-5af8cbfceb.zip b/.yarn/cache/deep-equal-npm-1.0.1-f05565c4e5-5af8cbfceb.zip new file mode 100644 index 00000000000..077864eb855 Binary files /dev/null and b/.yarn/cache/deep-equal-npm-1.0.1-f05565c4e5-5af8cbfceb.zip differ diff --git a/.yarn/cache/devalue-npm-5.8.2-672994f1db-1ad55c5d45.zip b/.yarn/cache/devalue-npm-5.8.2-672994f1db-1ad55c5d45.zip new file mode 100644 index 00000000000..ffa3f141c91 Binary files /dev/null and b/.yarn/cache/devalue-npm-5.8.2-672994f1db-1ad55c5d45.zip differ diff --git a/.yarn/cache/dezalgo-npm-1.0.4-ae3b673c98-895389c6ae.zip b/.yarn/cache/dezalgo-npm-1.0.4-ae3b673c98-895389c6ae.zip new file mode 100644 index 00000000000..14a446ae25f Binary files /dev/null and b/.yarn/cache/dezalgo-npm-1.0.4-ae3b673c98-895389c6ae.zip differ diff --git a/.yarn/cache/dunder-proto-npm-1.0.1-90eb6829db-149207e36f.zip b/.yarn/cache/dunder-proto-npm-1.0.1-90eb6829db-149207e36f.zip new file mode 100644 index 00000000000..930579f0055 Binary files /dev/null and b/.yarn/cache/dunder-proto-npm-1.0.1-90eb6829db-149207e36f.zip differ diff --git a/.yarn/cache/electron-to-chromium-npm-1.5.396-b770b05044-e5d7856db1.zip b/.yarn/cache/electron-to-chromium-npm-1.5.396-b770b05044-e5d7856db1.zip new file mode 100644 index 00000000000..dde5ecf4601 Binary files /dev/null and b/.yarn/cache/electron-to-chromium-npm-1.5.396-b770b05044-e5d7856db1.zip differ diff --git a/.yarn/cache/es-define-property-npm-1.0.1-3fc6324f1c-0512f4e5d5.zip b/.yarn/cache/es-define-property-npm-1.0.1-3fc6324f1c-0512f4e5d5.zip new file mode 100644 index 00000000000..96e58e9ba21 Binary files /dev/null and b/.yarn/cache/es-define-property-npm-1.0.1-3fc6324f1c-0512f4e5d5.zip differ diff --git a/.yarn/cache/es-errors-npm-1.3.0-fda0c9b8a8-ec1414527a.zip b/.yarn/cache/es-errors-npm-1.3.0-fda0c9b8a8-ec1414527a.zip new file mode 100644 index 00000000000..0ed2323fcdd Binary files /dev/null and b/.yarn/cache/es-errors-npm-1.3.0-fda0c9b8a8-ec1414527a.zip differ diff --git a/.yarn/cache/es-object-atoms-npm-1.1.2-97972d8992-b821f39e4f.zip b/.yarn/cache/es-object-atoms-npm-1.1.2-97972d8992-b821f39e4f.zip new file mode 100644 index 00000000000..73786cf3921 Binary files /dev/null and b/.yarn/cache/es-object-atoms-npm-1.1.2-97972d8992-b821f39e4f.zip differ diff --git a/.yarn/cache/esm-env-npm-1.2.2-c6981cc52f-3fb28f6f84.zip b/.yarn/cache/esm-env-npm-1.2.2-c6981cc52f-3fb28f6f84.zip new file mode 100644 index 00000000000..58cd471fe5b Binary files /dev/null and b/.yarn/cache/esm-env-npm-1.2.2-c6981cc52f-3fb28f6f84.zip differ diff --git a/.yarn/cache/esrap-npm-2.3.0-03bb5f2b34-df476c3c71.zip b/.yarn/cache/esrap-npm-2.3.0-03bb5f2b34-df476c3c71.zip new file mode 100644 index 00000000000..f58bc27fddc Binary files /dev/null and b/.yarn/cache/esrap-npm-2.3.0-03bb5f2b34-df476c3c71.zip differ diff --git a/.yarn/cache/estree-walker-npm-2.0.2-dfab42f65c-6151e6f982.zip b/.yarn/cache/estree-walker-npm-2.0.2-dfab42f65c-6151e6f982.zip new file mode 100644 index 00000000000..71b90a2f2c5 Binary files /dev/null and b/.yarn/cache/estree-walker-npm-2.0.2-dfab42f65c-6151e6f982.zip differ diff --git a/.yarn/cache/foreachasync-npm-3.0.0-c8ac3c5fca-4791f64b53.zip b/.yarn/cache/foreachasync-npm-3.0.0-c8ac3c5fca-4791f64b53.zip new file mode 100644 index 00000000000..557ba6beb67 Binary files /dev/null and b/.yarn/cache/foreachasync-npm-3.0.0-c8ac3c5fca-4791f64b53.zip differ diff --git a/.yarn/cache/formidable-npm-3.5.4-a3473998f7-bdb8ecd8af.zip b/.yarn/cache/formidable-npm-3.5.4-a3473998f7-bdb8ecd8af.zip new file mode 100644 index 00000000000..51b11111052 Binary files /dev/null and b/.yarn/cache/formidable-npm-3.5.4-a3473998f7-bdb8ecd8af.zip differ diff --git a/.yarn/cache/function-bind-npm-1.1.2-7a55be9b03-2b0ff4ce70.zip b/.yarn/cache/function-bind-npm-1.1.2-7a55be9b03-2b0ff4ce70.zip new file mode 100644 index 00000000000..55fbdad3a3b Binary files /dev/null and b/.yarn/cache/function-bind-npm-1.1.2-7a55be9b03-2b0ff4ce70.zip differ diff --git a/.yarn/cache/generator-function-npm-2.0.1-aed34a724a-3bf87f7b02.zip b/.yarn/cache/generator-function-npm-2.0.1-aed34a724a-3bf87f7b02.zip new file mode 100644 index 00000000000..2f58611029e Binary files /dev/null and b/.yarn/cache/generator-function-npm-2.0.1-aed34a724a-3bf87f7b02.zip differ diff --git a/.yarn/cache/get-intrinsic-npm-1.3.1-2f734f40ec-c02b3b6a44.zip b/.yarn/cache/get-intrinsic-npm-1.3.1-2f734f40ec-c02b3b6a44.zip new file mode 100644 index 00000000000..84295d83808 Binary files /dev/null and b/.yarn/cache/get-intrinsic-npm-1.3.1-2f734f40ec-c02b3b6a44.zip differ diff --git a/.yarn/cache/get-proto-npm-1.0.1-4d30bac614-4fc96afdb5.zip b/.yarn/cache/get-proto-npm-1.0.1-4d30bac614-4fc96afdb5.zip new file mode 100644 index 00000000000..65fbfe076a6 Binary files /dev/null and b/.yarn/cache/get-proto-npm-1.0.1-4d30bac614-4fc96afdb5.zip differ diff --git a/.yarn/cache/gettext-parser-npm-6.0.0-578610da43-e6938755d9.zip b/.yarn/cache/gettext-parser-npm-6.0.0-578610da43-e6938755d9.zip new file mode 100644 index 00000000000..dc401765652 Binary files /dev/null and b/.yarn/cache/gettext-parser-npm-6.0.0-578610da43-e6938755d9.zip differ diff --git a/.yarn/cache/glob-npm-13.0.0-8e50143ca8-963730222b.zip b/.yarn/cache/glob-npm-13.0.0-8e50143ca8-963730222b.zip new file mode 100644 index 00000000000..18d4add682b Binary files /dev/null and b/.yarn/cache/glob-npm-13.0.0-8e50143ca8-963730222b.zip differ diff --git a/.yarn/cache/gopd-npm-1.2.0-df89ffa78e-cc6d8e655e.zip b/.yarn/cache/gopd-npm-1.2.0-df89ffa78e-cc6d8e655e.zip new file mode 100644 index 00000000000..54fd29f161a Binary files /dev/null and b/.yarn/cache/gopd-npm-1.2.0-df89ffa78e-cc6d8e655e.zip differ diff --git a/.yarn/cache/has-ansi-npm-2.0.0-9bf0cff2af-1b51daa021.zip b/.yarn/cache/has-ansi-npm-2.0.0-9bf0cff2af-1b51daa021.zip new file mode 100644 index 00000000000..61a5a3439fb Binary files /dev/null and b/.yarn/cache/has-ansi-npm-2.0.0-9bf0cff2af-1b51daa021.zip differ diff --git a/.yarn/cache/has-symbols-npm-1.1.0-9aa7dc2ac1-b2316c7302.zip b/.yarn/cache/has-symbols-npm-1.1.0-9aa7dc2ac1-b2316c7302.zip new file mode 100644 index 00000000000..cba99a47e49 Binary files /dev/null and b/.yarn/cache/has-symbols-npm-1.1.0-9aa7dc2ac1-b2316c7302.zip differ diff --git a/.yarn/cache/has-tostringtag-npm-1.0.2-74a4800369-999d60bb75.zip b/.yarn/cache/has-tostringtag-npm-1.0.2-74a4800369-999d60bb75.zip new file mode 100644 index 00000000000..012a7256174 Binary files /dev/null and b/.yarn/cache/has-tostringtag-npm-1.0.2-74a4800369-999d60bb75.zip differ diff --git a/.yarn/cache/hasown-npm-2.0.4-75e16c9c2a-4bd8f916b6.zip b/.yarn/cache/hasown-npm-2.0.4-75e16c9c2a-4bd8f916b6.zip new file mode 100644 index 00000000000..8a33f0e81dd Binary files /dev/null and b/.yarn/cache/hasown-npm-2.0.4-75e16c9c2a-4bd8f916b6.zip differ diff --git a/.yarn/cache/http-assert-npm-1.5.0-bf7ea4ffcf-69c9b3c14c.zip b/.yarn/cache/http-assert-npm-1.5.0-bf7ea4ffcf-69c9b3c14c.zip new file mode 100644 index 00000000000..989ef7de635 Binary files /dev/null and b/.yarn/cache/http-assert-npm-1.5.0-bf7ea4ffcf-69c9b3c14c.zip differ diff --git a/.yarn/cache/http-errors-npm-1.8.1-fb60d9f6ae-d3c7e7e776.zip b/.yarn/cache/http-errors-npm-1.8.1-fb60d9f6ae-d3c7e7e776.zip new file mode 100644 index 00000000000..2fb70ddd0d4 Binary files /dev/null and b/.yarn/cache/http-errors-npm-1.8.1-fb60d9f6ae-d3c7e7e776.zip differ diff --git a/.yarn/cache/http-errors-npm-2.0.1-6d19ab492e-155d1a100a.zip b/.yarn/cache/http-errors-npm-2.0.1-6d19ab492e-155d1a100a.zip new file mode 100644 index 00000000000..f1b502b5cfd Binary files /dev/null and b/.yarn/cache/http-errors-npm-2.0.1-6d19ab492e-155d1a100a.zip differ diff --git a/.yarn/cache/hunspell-spellchecker-npm-1.0.2-57766038b1-098e00a705.zip b/.yarn/cache/hunspell-spellchecker-npm-1.0.2-57766038b1-098e00a705.zip new file mode 100644 index 00000000000..77e08dc93d9 Binary files /dev/null and b/.yarn/cache/hunspell-spellchecker-npm-1.0.2-57766038b1-098e00a705.zip differ diff --git a/.yarn/cache/import-fresh-npm-3.3.1-1916794950-a06b19461b.zip b/.yarn/cache/import-fresh-npm-3.3.1-1916794950-a06b19461b.zip new file mode 100644 index 00000000000..7157798f3ac Binary files /dev/null and b/.yarn/cache/import-fresh-npm-3.3.1-1916794950-a06b19461b.zip differ diff --git a/.yarn/cache/inflation-npm-2.1.0-df5ba7218d-80c1b5d9ec.zip b/.yarn/cache/inflation-npm-2.1.0-df5ba7218d-80c1b5d9ec.zip new file mode 100644 index 00000000000..dc69f29d796 Binary files /dev/null and b/.yarn/cache/inflation-npm-2.1.0-df5ba7218d-80c1b5d9ec.zip differ diff --git a/.yarn/cache/is-core-module-npm-2.16.2-f7b0e85c93-9317844b49.zip b/.yarn/cache/is-core-module-npm-2.16.2-f7b0e85c93-9317844b49.zip new file mode 100644 index 00000000000..cc336afee4f Binary files /dev/null and b/.yarn/cache/is-core-module-npm-2.16.2-f7b0e85c93-9317844b49.zip differ diff --git a/.yarn/cache/is-generator-function-npm-1.1.2-d0a84b1a72-0b81c61375.zip b/.yarn/cache/is-generator-function-npm-1.1.2-d0a84b1a72-0b81c61375.zip new file mode 100644 index 00000000000..b2e44c6cbab Binary files /dev/null and b/.yarn/cache/is-generator-function-npm-1.1.2-d0a84b1a72-0b81c61375.zip differ diff --git a/.yarn/cache/is-reference-npm-3.0.3-2edaf1be22-11371fb266.zip b/.yarn/cache/is-reference-npm-3.0.3-2edaf1be22-11371fb266.zip new file mode 100644 index 00000000000..286ab577122 Binary files /dev/null and b/.yarn/cache/is-reference-npm-3.0.3-2edaf1be22-11371fb266.zip differ diff --git a/.yarn/cache/is-regex-npm-1.2.1-70a484f2c8-99ee0b6d30.zip b/.yarn/cache/is-regex-npm-1.2.1-70a484f2c8-99ee0b6d30.zip new file mode 100644 index 00000000000..735e8a47fe0 Binary files /dev/null and b/.yarn/cache/is-regex-npm-1.2.1-70a484f2c8-99ee0b6d30.zip differ diff --git a/.yarn/cache/keygrip-npm-1.1.0-8da030c3ff-078cd16a46.zip b/.yarn/cache/keygrip-npm-1.1.0-8da030c3ff-078cd16a46.zip new file mode 100644 index 00000000000..1d25b57ccc0 Binary files /dev/null and b/.yarn/cache/keygrip-npm-1.1.0-8da030c3ff-078cd16a46.zip differ diff --git a/.yarn/cache/koa-body-npm-7.0.1-7b8ce86e4b-ec9783225a.zip b/.yarn/cache/koa-body-npm-7.0.1-7b8ce86e4b-ec9783225a.zip new file mode 100644 index 00000000000..d217673f580 Binary files /dev/null and b/.yarn/cache/koa-body-npm-7.0.1-7b8ce86e4b-ec9783225a.zip differ diff --git a/.yarn/cache/koa-compose-npm-4.1.0-b682d9324e-46cb16792d.zip b/.yarn/cache/koa-compose-npm-4.1.0-b682d9324e-46cb16792d.zip new file mode 100644 index 00000000000..e901342a4fb Binary files /dev/null and b/.yarn/cache/koa-compose-npm-4.1.0-b682d9324e-46cb16792d.zip differ diff --git a/.yarn/cache/koa-convert-npm-2.0.0-d709eca55c-7385b33919.zip b/.yarn/cache/koa-convert-npm-2.0.0-d709eca55c-7385b33919.zip new file mode 100644 index 00000000000..d73061b4946 Binary files /dev/null and b/.yarn/cache/koa-convert-npm-2.0.0-d709eca55c-7385b33919.zip differ diff --git a/.yarn/cache/koa-npm-2.16.4-af02a0a309-117cacd60e.zip b/.yarn/cache/koa-npm-2.16.4-af02a0a309-117cacd60e.zip new file mode 100644 index 00000000000..73edd568967 Binary files /dev/null and b/.yarn/cache/koa-npm-2.16.4-af02a0a309-117cacd60e.zip differ diff --git a/.yarn/cache/koa-router-npm-14.0.0-d159e7a449-8e948c2f53.zip b/.yarn/cache/koa-router-npm-14.0.0-d159e7a449-8e948c2f53.zip new file mode 100644 index 00000000000..9e8220795be Binary files /dev/null and b/.yarn/cache/koa-router-npm-14.0.0-d159e7a449-8e948c2f53.zip differ diff --git a/.yarn/cache/locate-character-npm-3.0.0-40928dccbb-2d9e9f45e2.zip b/.yarn/cache/locate-character-npm-3.0.0-40928dccbb-2d9e9f45e2.zip new file mode 100644 index 00000000000..f2f507648e5 Binary files /dev/null and b/.yarn/cache/locate-character-npm-3.0.0-40928dccbb-2d9e9f45e2.zip differ diff --git a/.yarn/cache/lodash.mapvalues-npm-4.6.0-4664380119-0ff1b252fd.zip b/.yarn/cache/lodash.mapvalues-npm-4.6.0-4664380119-0ff1b252fd.zip new file mode 100644 index 00000000000..063b2daa6e2 Binary files /dev/null and b/.yarn/cache/lodash.mapvalues-npm-4.6.0-4664380119-0ff1b252fd.zip differ diff --git a/.yarn/cache/log-symbols-npm-1.0.2-2224ede6fd-5214ade938.zip b/.yarn/cache/log-symbols-npm-1.0.2-2224ede6fd-5214ade938.zip new file mode 100644 index 00000000000..ed1a19e8a74 Binary files /dev/null and b/.yarn/cache/log-symbols-npm-1.0.2-2224ede6fd-5214ade938.zip differ diff --git a/.yarn/cache/magic-string-npm-0.30.21-9a226cb21e-4ff76a4e8d.zip b/.yarn/cache/magic-string-npm-0.30.21-9a226cb21e-4ff76a4e8d.zip new file mode 100644 index 00000000000..7ad2eda118d Binary files /dev/null and b/.yarn/cache/magic-string-npm-0.30.21-9a226cb21e-4ff76a4e8d.zip differ diff --git a/.yarn/cache/math-intrinsics-npm-1.1.0-9204d80e7d-0e513b29d1.zip b/.yarn/cache/math-intrinsics-npm-1.1.0-9204d80e7d-0e513b29d1.zip new file mode 100644 index 00000000000..5614ed5bc10 Binary files /dev/null and b/.yarn/cache/math-intrinsics-npm-1.1.0-9204d80e7d-0e513b29d1.zip differ diff --git a/.yarn/cache/mimic-fn-npm-1.2.0-960bf15ab7-69c0820515.zip b/.yarn/cache/mimic-fn-npm-1.2.0-960bf15ab7-69c0820515.zip new file mode 100644 index 00000000000..ae711478fd8 Binary files /dev/null and b/.yarn/cache/mimic-fn-npm-1.2.0-960bf15ab7-69c0820515.zip differ diff --git a/.yarn/cache/node-releases-npm-2.0.51-79864dfd85-0d607ebc5c.zip b/.yarn/cache/node-releases-npm-2.0.51-79864dfd85-0d607ebc5c.zip new file mode 100644 index 00000000000..9741ad273f1 Binary files /dev/null and b/.yarn/cache/node-releases-npm-2.0.51-79864dfd85-0d607ebc5c.zip differ diff --git a/.yarn/cache/object-inspect-npm-1.13.4-4e741f9806-582810c6a8.zip b/.yarn/cache/object-inspect-npm-1.13.4-4e741f9806-582810c6a8.zip new file mode 100644 index 00000000000..fbe764992ec Binary files /dev/null and b/.yarn/cache/object-inspect-npm-1.13.4-4e741f9806-582810c6a8.zip differ diff --git a/.yarn/cache/onetime-npm-2.0.1-6c39ecc911-bb44015ac7.zip b/.yarn/cache/onetime-npm-2.0.1-6c39ecc911-bb44015ac7.zip new file mode 100644 index 00000000000..df76b4087bf Binary files /dev/null and b/.yarn/cache/onetime-npm-2.0.1-6c39ecc911-bb44015ac7.zip differ diff --git a/.yarn/cache/only-npm-0.0.2-122402a3f9-d399710db8.zip b/.yarn/cache/only-npm-0.0.2-122402a3f9-d399710db8.zip new file mode 100644 index 00000000000..5b8e8de42e9 Binary files /dev/null and b/.yarn/cache/only-npm-0.0.2-122402a3f9-d399710db8.zip differ diff --git a/.yarn/cache/ora-npm-1.3.0-e1380dba55-241a8e1038.zip b/.yarn/cache/ora-npm-1.3.0-e1380dba55-241a8e1038.zip new file mode 100644 index 00000000000..6b503e6a6b6 Binary files /dev/null and b/.yarn/cache/ora-npm-1.3.0-e1380dba55-241a8e1038.zip differ diff --git a/.yarn/cache/path-to-regexp-npm-8.4.2-5602ed344b-c30fba443e.zip b/.yarn/cache/path-to-regexp-npm-8.4.2-5602ed344b-c30fba443e.zip new file mode 100644 index 00000000000..dcb7bbef8c3 Binary files /dev/null and b/.yarn/cache/path-to-regexp-npm-8.4.2-5602ed344b-c30fba443e.zip differ diff --git a/.yarn/cache/plural-forms-npm-0.5.3-c329abd5ba-3672f25d29.zip b/.yarn/cache/plural-forms-npm-0.5.3-c329abd5ba-3672f25d29.zip new file mode 100644 index 00000000000..5fb3a968b29 Binary files /dev/null and b/.yarn/cache/plural-forms-npm-0.5.3-c329abd5ba-3672f25d29.zip differ diff --git a/.yarn/cache/qs-npm-6.15.3-47907326d2-b59a0f2049.zip b/.yarn/cache/qs-npm-6.15.3-47907326d2-b59a0f2049.zip new file mode 100644 index 00000000000..9360ad35ddf Binary files /dev/null and b/.yarn/cache/qs-npm-6.15.3-47907326d2-b59a0f2049.zip differ diff --git a/.yarn/cache/raw-body-npm-2.5.3-bcb2281e9c-16aa51e504.zip b/.yarn/cache/raw-body-npm-2.5.3-bcb2281e9c-16aa51e504.zip new file mode 100644 index 00000000000..3623b559929 Binary files /dev/null and b/.yarn/cache/raw-body-npm-2.5.3-bcb2281e9c-16aa51e504.zip differ diff --git a/.yarn/cache/readable-stream-npm-4.7.0-2aa0761036-03ec762fae.zip b/.yarn/cache/readable-stream-npm-4.7.0-2aa0761036-03ec762fae.zip new file mode 100644 index 00000000000..fe89b3dbce2 Binary files /dev/null and b/.yarn/cache/readable-stream-npm-4.7.0-2aa0761036-03ec762fae.zip differ diff --git a/.yarn/cache/readline-sync-npm-1.4.10-6809f52ca7-4dbd8925af.zip b/.yarn/cache/readline-sync-npm-1.4.10-6809f52ca7-4dbd8925af.zip new file mode 100644 index 00000000000..979f0629091 Binary files /dev/null and b/.yarn/cache/readline-sync-npm-1.4.10-6809f52ca7-4dbd8925af.zip differ diff --git a/.yarn/cache/regenerate-unicode-properties-npm-10.2.2-7d116b2ed9-7ae4c1c324.zip b/.yarn/cache/regenerate-unicode-properties-npm-10.2.2-7d116b2ed9-7ae4c1c324.zip new file mode 100644 index 00000000000..3d47e44ad9f Binary files /dev/null and b/.yarn/cache/regenerate-unicode-properties-npm-10.2.2-7d116b2ed9-7ae4c1c324.zip differ diff --git a/.yarn/cache/regexpu-core-npm-6.4.0-8966e0bc82-a316eb9885.zip b/.yarn/cache/regexpu-core-npm-6.4.0-8966e0bc82-a316eb9885.zip new file mode 100644 index 00000000000..53d43650f01 Binary files /dev/null and b/.yarn/cache/regexpu-core-npm-6.4.0-8966e0bc82-a316eb9885.zip differ diff --git a/.yarn/cache/regjsparser-npm-0.13.2-65efa7ba27-20ece45a3e.zip b/.yarn/cache/regjsparser-npm-0.13.2-65efa7ba27-20ece45a3e.zip new file mode 100644 index 00000000000..126c3a4e730 Binary files /dev/null and b/.yarn/cache/regjsparser-npm-0.13.2-65efa7ba27-20ece45a3e.zip differ diff --git a/.yarn/cache/resolve-npm-1.22.12-36aa35b43a-4dc5a614b3.zip b/.yarn/cache/resolve-npm-1.22.12-36aa35b43a-4dc5a614b3.zip new file mode 100644 index 00000000000..1020818402c Binary files /dev/null and b/.yarn/cache/resolve-npm-1.22.12-36aa35b43a-4dc5a614b3.zip differ diff --git a/.yarn/cache/resolve-patch-d39a369b59-0cc5b060cb.zip b/.yarn/cache/resolve-patch-d39a369b59-0cc5b060cb.zip new file mode 100644 index 00000000000..df866a90fb3 Binary files /dev/null and b/.yarn/cache/resolve-patch-d39a369b59-0cc5b060cb.zip differ diff --git a/.yarn/cache/restore-cursor-npm-2.0.0-80278eb6b7-482e13d02d.zip b/.yarn/cache/restore-cursor-npm-2.0.0-80278eb6b7-482e13d02d.zip new file mode 100644 index 00000000000..3b01b88c0e1 Binary files /dev/null and b/.yarn/cache/restore-cursor-npm-2.0.0-80278eb6b7-482e13d02d.zip differ diff --git a/.yarn/cache/safe-regex-test-npm-1.1.0-453eb81b83-3c809abeb8.zip b/.yarn/cache/safe-regex-test-npm-1.1.0-453eb81b83-3c809abeb8.zip new file mode 100644 index 00000000000..a0b7b26a012 Binary files /dev/null and b/.yarn/cache/safe-regex-test-npm-1.1.0-453eb81b83-3c809abeb8.zip differ diff --git a/.yarn/cache/serialize-javascript-npm-7.0.7-6fd9a2397a-197edeab01.zip b/.yarn/cache/serialize-javascript-npm-7.0.7-6fd9a2397a-197edeab01.zip new file mode 100644 index 00000000000..2ee3e505525 Binary files /dev/null and b/.yarn/cache/serialize-javascript-npm-7.0.7-6fd9a2397a-197edeab01.zip differ diff --git a/.yarn/cache/side-channel-list-npm-1.0.1-7a0802d399-3499671cd5.zip b/.yarn/cache/side-channel-list-npm-1.0.1-7a0802d399-3499671cd5.zip new file mode 100644 index 00000000000..d163f0ac032 Binary files /dev/null and b/.yarn/cache/side-channel-list-npm-1.0.1-7a0802d399-3499671cd5.zip differ diff --git a/.yarn/cache/side-channel-map-npm-1.0.1-5903573b3c-42501371cd.zip b/.yarn/cache/side-channel-map-npm-1.0.1-5903573b3c-42501371cd.zip new file mode 100644 index 00000000000..ae704d0896d Binary files /dev/null and b/.yarn/cache/side-channel-map-npm-1.0.1-5903573b3c-42501371cd.zip differ diff --git a/.yarn/cache/side-channel-npm-1.1.1-3d97a5a6fb-e0f217140c.zip b/.yarn/cache/side-channel-npm-1.1.1-3d97a5a6fb-e0f217140c.zip new file mode 100644 index 00000000000..474c92387f8 Binary files /dev/null and b/.yarn/cache/side-channel-npm-1.1.1-3d97a5a6fb-e0f217140c.zip differ diff --git a/.yarn/cache/side-channel-weakmap-npm-1.0.2-027acaf499-a815c89bc7.zip b/.yarn/cache/side-channel-weakmap-npm-1.0.2-027acaf499-a815c89bc7.zip new file mode 100644 index 00000000000..9e15dea675a Binary files /dev/null and b/.yarn/cache/side-channel-weakmap-npm-1.0.2-027acaf499-a815c89bc7.zip differ diff --git a/.yarn/cache/statuses-npm-2.0.2-2d84c63b8c-6927feb50c.zip b/.yarn/cache/statuses-npm-2.0.2-2d84c63b8c-6927feb50c.zip new file mode 100644 index 00000000000..61790da7a51 Binary files /dev/null and b/.yarn/cache/statuses-npm-2.0.2-2d84c63b8c-6927feb50c.zip differ diff --git a/.yarn/cache/strip-ansi-npm-3.0.1-6aec1365b9-9b974de611.zip b/.yarn/cache/strip-ansi-npm-3.0.1-6aec1365b9-9b974de611.zip new file mode 100644 index 00000000000..a1c9f6a0b62 Binary files /dev/null and b/.yarn/cache/strip-ansi-npm-3.0.1-6aec1365b9-9b974de611.zip differ diff --git a/.yarn/cache/supports-color-npm-2.0.0-22c0f0adbc-602538c581.zip b/.yarn/cache/supports-color-npm-2.0.0-22c0f0adbc-602538c581.zip new file mode 100644 index 00000000000..c4608ecfe95 Binary files /dev/null and b/.yarn/cache/supports-color-npm-2.0.0-22c0f0adbc-602538c581.zip differ diff --git a/.yarn/cache/svelte-npm-5.56.8-a5abc8fab7-3ccdb287aa.zip b/.yarn/cache/svelte-npm-5.56.8-a5abc8fab7-3ccdb287aa.zip new file mode 100644 index 00000000000..d93e43b65f7 Binary files /dev/null and b/.yarn/cache/svelte-npm-5.56.8-a5abc8fab7-3ccdb287aa.zip differ diff --git a/.yarn/cache/tagged-tag-npm-1.0.0-80e0c0061d-e37653df3e.zip b/.yarn/cache/tagged-tag-npm-1.0.0-80e0c0061d-e37653df3e.zip new file mode 100644 index 00000000000..53c28675ba8 Binary files /dev/null and b/.yarn/cache/tagged-tag-npm-1.0.0-80e0c0061d-e37653df3e.zip differ diff --git a/.yarn/cache/tmp-npm-0.2.7-a6fd3441a0-45dec2fc28.zip b/.yarn/cache/tmp-npm-0.2.7-a6fd3441a0-45dec2fc28.zip new file mode 100644 index 00000000000..8a5516b7464 Binary files /dev/null and b/.yarn/cache/tmp-npm-0.2.7-a6fd3441a0-45dec2fc28.zip differ diff --git a/.yarn/cache/tsscmp-npm-1.0.6-3223087558-1512384def.zip b/.yarn/cache/tsscmp-npm-1.0.6-3223087558-1512384def.zip new file mode 100644 index 00000000000..f7a4759c766 Binary files /dev/null and b/.yarn/cache/tsscmp-npm-1.0.6-3223087558-1512384def.zip differ diff --git a/.yarn/cache/ttag-cli-npm-1.12.0-b1019c321e-fbd667433a.zip b/.yarn/cache/ttag-cli-npm-1.12.0-b1019c321e-fbd667433a.zip new file mode 100644 index 00000000000..8f38d80f221 Binary files /dev/null and b/.yarn/cache/ttag-cli-npm-1.12.0-b1019c321e-fbd667433a.zip differ diff --git a/.yarn/cache/type-fest-npm-5.8.0-5434a948b7-d234cd3ad6.zip b/.yarn/cache/type-fest-npm-5.8.0-5434a948b7-d234cd3ad6.zip new file mode 100644 index 00000000000..fc348913342 Binary files /dev/null and b/.yarn/cache/type-fest-npm-5.8.0-5434a948b7-d234cd3ad6.zip differ diff --git a/.yarn/cache/unicode-match-property-value-ecmascript-npm-2.2.1-0b3c4504a2-e6c73e07bb.zip b/.yarn/cache/unicode-match-property-value-ecmascript-npm-2.2.1-0b3c4504a2-e6c73e07bb.zip new file mode 100644 index 00000000000..3ebf331f221 Binary files /dev/null and b/.yarn/cache/unicode-match-property-value-ecmascript-npm-2.2.1-0b3c4504a2-e6c73e07bb.zip differ diff --git a/.yarn/cache/update-browserslist-db-npm-1.2.3-de1d320326-6f209a97ae.zip b/.yarn/cache/update-browserslist-db-npm-1.2.3-de1d320326-6f209a97ae.zip new file mode 100644 index 00000000000..d33ce80e8bf Binary files /dev/null and b/.yarn/cache/update-browserslist-db-npm-1.2.3-de1d320326-6f209a97ae.zip differ diff --git a/.yarn/cache/vue-sfc-parser-npm-0.1.2-f976243291-24f79fc4d7.zip b/.yarn/cache/vue-sfc-parser-npm-0.1.2-f976243291-24f79fc4d7.zip new file mode 100644 index 00000000000..9df2f12d33c Binary files /dev/null and b/.yarn/cache/vue-sfc-parser-npm-0.1.2-f976243291-24f79fc4d7.zip differ diff --git a/.yarn/cache/walk-npm-2.3.9-9084777c89-6b55cd4cac.zip b/.yarn/cache/walk-npm-2.3.9-9084777c89-6b55cd4cac.zip new file mode 100644 index 00000000000..b726e189933 Binary files /dev/null and b/.yarn/cache/walk-npm-2.3.9-9084777c89-6b55cd4cac.zip differ diff --git a/.yarn/cache/yaml-npm-1.10.3-df9008b926-6a2dd3582f.zip b/.yarn/cache/yaml-npm-1.10.3-df9008b926-6a2dd3582f.zip new file mode 100644 index 00000000000..12acf9cffed Binary files /dev/null and b/.yarn/cache/yaml-npm-1.10.3-df9008b926-6a2dd3582f.zip differ diff --git a/.yarn/cache/yargs-npm-16.2.2-72eb4a72b8-0619aaa93d.zip b/.yarn/cache/yargs-npm-16.2.2-72eb4a72b8-0619aaa93d.zip new file mode 100644 index 00000000000..c3ebe41e255 Binary files /dev/null and b/.yarn/cache/yargs-npm-16.2.2-72eb4a72b8-0619aaa93d.zip differ diff --git a/.yarn/cache/ylru-npm-1.4.0-f1b70f7a8e-e0bf797476.zip b/.yarn/cache/ylru-npm-1.4.0-f1b70f7a8e-e0bf797476.zip new file mode 100644 index 00000000000..35207833016 Binary files /dev/null and b/.yarn/cache/ylru-npm-1.4.0-f1b70f7a8e-e0bf797476.zip differ diff --git a/.yarn/cache/zimmerframe-npm-1.1.4-a2c339a65f-f7917916db.zip b/.yarn/cache/zimmerframe-npm-1.1.4-a2c339a65f-f7917916db.zip new file mode 100644 index 00000000000..55e182c1f45 Binary files /dev/null and b/.yarn/cache/zimmerframe-npm-1.1.4-a2c339a65f-f7917916db.zip differ diff --git a/.yarn/cache/zod-npm-4.4.3-36e81f791e-bf236fdee7.zip b/.yarn/cache/zod-npm-4.4.3-36e81f791e-bf236fdee7.zip new file mode 100644 index 00000000000..a92fde6bc4e Binary files /dev/null and b/.yarn/cache/zod-npm-4.4.3-36e81f791e-bf236fdee7.zip differ diff --git a/package.json b/package.json index 7e3c91cfaab..1662e82644a 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "changelog:json": "node scripts/ChangelogToJson.js && git add .", "postversion": "./scripts/push-tags-one-by-one.sh", "workspace:list": " yarn lerna list -all", - "upgrade:snjs": "ncu -u '@standardnotes/*' && yarn workspaces foreach --verbose run upgrade:snjs" + "upgrade:snjs": "ncu -u '@standardnotes/*' && yarn workspaces foreach --verbose run upgrade:snjs", + "i18n:extract": "yarn workspace @standardnotes/web i18n:extract && yarn workspace @standardnotes/desktop i18n:extract && yarn workspace @standardnotes/mobile i18n:extract && echo 'translations extracted'" }, "resolutions": { "@types/styled-components/@types/react": "17.0.2", @@ -70,6 +71,7 @@ "npm-check-updates": "^16.10.17", "prettier": "3.0.0", "sass-loader": "^13.3.2", + "ttag-cli": "^1.11.2", "typescript": "5.8.3", "webpack": "^5.88.2", "webpack-cli": "^5.1.4", diff --git a/packages/api/package.json b/packages/api/package.json index 7fb76ce3a20..924fd00effd 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -40,6 +40,7 @@ "@standardnotes/models": "workspace:*", "@standardnotes/responses": "workspace:*", "@standardnotes/utils": "workspace:*", - "reflect-metadata": "^0.1.13" + "reflect-metadata": "^0.1.13", + "ttag": "^1.8.12" } } diff --git a/packages/api/src/Domain/Error/ErrorMessage.ts b/packages/api/src/Domain/Error/ErrorMessage.ts index ab35cfcc8da..788a55ce917 100644 --- a/packages/api/src/Domain/Error/ErrorMessage.ts +++ b/packages/api/src/Domain/Error/ErrorMessage.ts @@ -1,9 +1,26 @@ -export enum ErrorMessage { - RegistrationInProgress = 'An existing registration request is already in progress.', - GenericRegistrationFail = 'A server error occurred while trying to register. Please try again.', - RateLimited = 'Too many successive server requests. Please wait a few minutes and try again.', - InsufficientPasswordMessage = 'Your password must be at least %LENGTH% characters in length. For your security, please choose a longer password or, ideally, a passphrase, and try again.', - PasscodeRequired = 'Your passcode is required in order to register for an account.', - GenericInProgress = 'An existing request is already in progress.', - GenericFail = 'A server error occurred. Please try again.', +import { c } from 'ttag' + +export const ErrorMessage = { + get RegistrationInProgress() { + return c('B1.Account.SignIn.Status').t`An existing registration request is already in progress.` + }, + get GenericRegistrationFail() { + return c('B1.Account.SignIn.Error').t`A server error occurred while trying to register. Please try again.` + }, + get RateLimited() { + return c('B2.NavSharedUI.Error').t`Too many successive server requests. Please wait a few minutes and try again.` + }, + get InsufficientPasswordMessage() { + return c('B1.Account.SignIn.Error') + .t`Your password must be at least %LENGTH% characters in length. For your security, please choose a longer password or, ideally, a passphrase, and try again.` + }, + get PasscodeRequired() { + return c('B1.Account.SignIn.Error').t`Your passcode is required in order to register for an account.` + }, + get GenericInProgress() { + return c('B2.NavSharedUI.Error').t`An existing request is already in progress.` + }, + get GenericFail() { + return c('B2.NavSharedUI.Error').t`A server error occurred. Please try again.` + }, } diff --git a/packages/desktop/app/javascripts/Main/File/FilesManager.ts b/packages/desktop/app/javascripts/Main/File/FilesManager.ts index e33db88edd7..3181e15198a 100644 --- a/packages/desktop/app/javascripts/Main/File/FilesManager.ts +++ b/packages/desktop/app/javascripts/Main/File/FilesManager.ts @@ -5,6 +5,7 @@ import { debounce } from 'lodash' import path from 'path' import yauzl from 'yauzl' import { Result } from '@standardnotes/domain-core' +import { c } from 'ttag' import { removeFromArray } from '../Utils/Utils' @@ -106,7 +107,7 @@ export class FilesManager implements FilesManagerInterface { try { fse.removeSync(dirPath) - return Result.ok('Directory deleted successfully') + return Result.ok(c('B8.MobileDesktopShared.Desktop.Info').t`Directory deleted successfully`) } catch (error) { return Result.fail((error as Error).message) } @@ -153,7 +154,7 @@ export class FilesManager implements FilesManagerInterface { try { await fse.move(dir, destination, { overwrite: true }) - return Result.ok('Directory moved successfully') + return Result.ok(c('B8.MobileDesktopShared.Desktop.Info').t`Directory moved successfully`) } catch (error) { return Result.fail((error as Error).message) } @@ -197,11 +198,13 @@ export class FilesManager implements FilesManagerInterface { destDir, ) - return Result.ok('Directory contents moved successfully') + return Result.ok(c('B8.MobileDesktopShared.Desktop.Info').t`Directory contents moved successfully`) } catch (error) { console.error(error) - return Result.fail(`Could not move directory contentes: ${(error as Error).message}`) + return Result.fail( + c('B8.MobileDesktopShared.Desktop.Error').t`Could not move directory contents: ${(error as Error).message}`, + ) } } diff --git a/packages/desktop/app/javascripts/Main/FileBackups/FileBackupsManager.ts b/packages/desktop/app/javascripts/Main/FileBackups/FileBackupsManager.ts index 56d4572a12a..60972e844ff 100644 --- a/packages/desktop/app/javascripts/Main/FileBackups/FileBackupsManager.ts +++ b/packages/desktop/app/javascripts/Main/FileBackups/FileBackupsManager.ts @@ -13,6 +13,7 @@ import { WebContents } from 'electron' import { StoreKeys } from '../Store/StoreKeys' import path from 'path' import { FileDownloader } from './FileDownloader' +import { c } from 'ttag' import { FileReadOperation } from './FileReadOperation' import { Paths } from '../Types/Paths' import { MessageToWebApp } from '../../Shared/IpcMessages' @@ -103,7 +104,7 @@ export class FilesBackupManager implements FileBackupsDevice { return savedLocation } - const LegacyTextBackupsDirectory = 'Standard Notes Backups' + const LegacyTextBackupsDirectory = c('B6.Preferences.Backups.Label').t`Standard Notes Backups` const homeDir = Paths.homeDir if (homeDir) { return path.join(homeDir, LegacyTextBackupsDirectory) diff --git a/packages/desktop/app/javascripts/Main/HomeServer/HomeServerManager.ts b/packages/desktop/app/javascripts/Main/HomeServer/HomeServerManager.ts index b98914ec598..81f49878fc8 100644 --- a/packages/desktop/app/javascripts/Main/HomeServer/HomeServerManager.ts +++ b/packages/desktop/app/javascripts/Main/HomeServer/HomeServerManager.ts @@ -1,5 +1,6 @@ import path from 'path' import os from 'os' +import { c } from 'ttag' import { HomeServerManagerInterface, @@ -83,7 +84,7 @@ export class HomeServerManager implements HomeServerManagerInterface { async setHomeServerConfiguration(configurationJSONString: string): Promise { try { if (!this.homeServerDataLocation) { - throw new Error('Home server data location is not set.') + throw new Error(c('B6.Preferences.HomeServer.Error').t`Home server data location is not set.`) } const homeServerConfiguration = JSON.parse(configurationJSONString) as HomeServerEnvironmentConfiguration @@ -93,11 +94,11 @@ export class HomeServerManager implements HomeServerManagerInterface { const configurationFile: HomeServerConfigurationFile = { version: '1.0.0', info: { - warning: 'Do not edit this file.', - information: - 'The values below are encrypted with a key created by the desktop application after installation. The key is stored in your secure device keychain.', - instructions: - 'Put this file inside your home server data location to restore your home server configuration.', + warning: c('B6.Preferences.Backups.Info').t`Do not edit this file.`, + information: c('B6.Preferences.HomeServer.Info') + .t`The values below are encrypted with a key created by the desktop application after installation. The key is stored in your secure device keychain.`, + instructions: c('B6.Preferences.HomeServer.Info') + .t`Put this file inside your home server data location to restore your home server configuration.`, }, configuration: homeServerConfiguration, } diff --git a/packages/desktop/app/javascripts/Main/Strings/english.ts b/packages/desktop/app/javascripts/Main/Strings/english.ts deleted file mode 100644 index 2cd1054e3eb..00000000000 --- a/packages/desktop/app/javascripts/Main/Strings/english.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { Strings } from './types' - -export function createEnglishStrings(): Strings { - return { - appMenu: { - edit: 'Edit', - view: 'View', - hideMenuBar: 'Hide Menu Bar', - useThemedMenuBar: 'Use Themed Menu Bar', - minimizeToTrayOnClose: 'Minimize To Tray On Close', - backups: 'Backups', - enableAutomaticUpdates: 'Enable Automatic Updates', - automaticUpdatesDisabled: 'Automatic Updates Disabled', - disableAutomaticBackups: 'Disable Automatic Backups', - enableAutomaticBackups: 'Enable Automatic Backups', - emailSupport: 'Email Support', - website: 'Website', - gitHub: 'GitHub', - discord: 'Discord', - twitter: 'Twitter', - toggleErrorConsole: 'Toggle Error Console', - openDataDirectory: 'Open Data Directory', - clearCacheAndReload: 'Clear Cache and Reload', - speech: 'Speech', - close: 'Close', - minimize: 'Minimize', - zoom: 'Zoom', - bringAllToFront: 'Bring All to Front', - checkForUpdate: 'Check for Update', - checkingForUpdate: 'Checking for update…', - updateAvailable: '(1) Update Available', - updates: 'Updates', - releaseNotes: 'Release Notes', - openDownloadLocation: 'Open Download Location', - downloadingUpdate: 'Downloading Update…', - manuallyDownloadUpdate: 'Manually Download Update', - spellcheckerLanguages: 'Spellchecker Languages', - installPendingUpdate(versionNumber: string) { - return `Install Pending Update (${versionNumber})` - }, - lastUpdateCheck(date: Date) { - return `Last checked ${date.toLocaleString()}` - }, - version(number: string) { - return `Version: ${number}` - }, - yourVersion(number: string) { - return `Your Version: ${number}` - }, - latestVersion(number: string) { - return `Latest Version: ${number}` - }, - viewReleaseNotes(versionNumber: string) { - return `View ${versionNumber} Release Notes` - }, - preferencesChanged: { - title: 'Preference Changed', - message: - 'Your menu bar preference has been saved. Please restart the ' + 'application for the change to take effect.', - }, - security: { - security: 'Security', - useKeyringtoStorePassword: 'Use password storage to store password', - enabledKeyringAccessMessage: - "Standard Notes will try to use your system's password storage " + - 'facility to store your password the next time you start it.', - enabledKeyringQuitNow: 'Quit Now', - enabledKeyringPostpone: 'Postpone', - }, - }, - contextMenu: { - learnSpelling: 'Learn Spelling', - noSuggestions: 'No Suggestions', - }, - tray: { - show: 'Show', - hide: 'Hide', - quit: 'Quit', - }, - extensions: { - missingExtension: - 'The extension was not found on your system, possibly because it is ' + - "still downloading. If the extension doesn't load, " + - 'try uninstalling then reinstalling the extension.', - unableToLoadExtension: - 'Unable to load extension. Please restart the application and ' + - 'try again. If the issue persists, try uninstalling then ' + - 'reinstalling the extension.', - }, - updates: { - automaticUpdatesEnabled: { - title: 'Automatic Updates Enabled.', - message: - 'Automatic updates have been enabled. Please note that ' + - 'this functionality is currently in beta, and that you are advised ' + - 'to periodically check in and ensure you are running the ' + - 'latest version.', - }, - finishedChecking: { - title: 'Finished checking for updates.', - error(description: string) { - return ( - 'An issue occurred while checking for updates. ' + - 'Please try again.\nIf this issue persists please contact ' + - `support with the following information: ${description}` - ) - }, - updateAvailable(newVersion: string) { - return ( - `A new update is available (version ${newVersion}). ` + - 'You can wait for the app to update itself, or manually ' + - 'download and install this update.' - ) - }, - noUpdateAvailable(currentVersion: string) { - return `Your version (${currentVersion}) is the latest available version.` - }, - }, - updateReady: { - title: 'Update Ready', - message(version: string) { - return `A new update (version ${version}) is ready to install.` - }, - quitAndInstall: 'Quit and Install', - installLater: 'Install Later', - noRecentBackupMessage: - 'An update is ready to install, but your backups folder does not ' + - 'appear to contain a recent enough backup. Please download a ' + - 'backup manually before proceeding with the installation.', - noRecentBackupDetail(lastBackupDate: number | null) { - const downloadInstructions = - 'You can download a backup from the Account menu ' + 'in the bottom-left corner of the app.' - const lastAutomaticBackup = - lastBackupDate === null - ? 'Your backups folder is empty.' - : `Your latest automatic backup is from ${new Date(lastBackupDate).toLocaleString()}.` - return `${downloadInstructions}\n${lastAutomaticBackup}` - }, - noRecentBackupChecbox: 'I have downloaded a backup, proceed with installation', - }, - errorDownloading: { - title: 'Error Downloading', - message: 'An error occurred while trying to download your ' + 'update file. Please try again.', - }, - unknownVersionName: 'Unknown', - }, - } -} diff --git a/packages/desktop/app/javascripts/Main/Strings/french.ts b/packages/desktop/app/javascripts/Main/Strings/french.ts deleted file mode 100644 index 6be8911d7ee..00000000000 --- a/packages/desktop/app/javascripts/Main/Strings/french.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { isDev } from '../Utils/Utils' -import { createEnglishStrings } from './english' -import { Strings } from './types' - -export function createFrenchStrings(): Strings { - const fallback = createEnglishStrings() - if (!isDev()) { - /** - * Le Français est une langue expérimentale. - * Don't show it in production yet. - */ - return fallback - } - return { - appMenu: { - ...fallback.appMenu, - edit: 'Édition', - view: 'Affichage', - }, - contextMenu: { - learnSpelling: "Mémoriser l'orthographe", - noSuggestions: 'Aucune suggestion', - }, - tray: { - show: 'Afficher', - hide: 'Masquer', - quit: 'Quitter', - }, - extensions: fallback.extensions, - updates: fallback.updates, - } -} diff --git a/packages/desktop/app/javascripts/Main/Strings/index.ts b/packages/desktop/app/javascripts/Main/Strings/index.ts index dd6fbc2c3b5..38e469046a8 100644 --- a/packages/desktop/app/javascripts/Main/Strings/index.ts +++ b/packages/desktop/app/javascripts/Main/Strings/index.ts @@ -1,6 +1,5 @@ import { isDev } from '../Utils/Utils' -import { createEnglishStrings } from './english' -import { createFrenchStrings } from './french' +import { createStrings } from './strings' import { Strings } from './types' let strings: Strings @@ -10,7 +9,7 @@ let strings: Strings * @param locale The user's locale * @see https://www.electronjs.org/docs/api/locales */ -export function initializeStrings(locale: string): void { +export function initializeStrings(_locale: string): void { if (isDev()) { if (strings) { throw new Error('`strings` has already been initialized') @@ -21,7 +20,7 @@ export function initializeStrings(locale: string): void { return } - strings = stringsForLocale(locale) + strings = createStrings() } export function str(): Strings { @@ -53,14 +52,4 @@ export function updates() { return str().updates } -function stringsForLocale(locale: string): Strings { - if (locale === 'en' || locale.startsWith('en-')) { - return createEnglishStrings() - } else if (locale === 'fr' || locale.startsWith('fr-')) { - return createFrenchStrings() - } - - return createEnglishStrings() -} - export const AppName = 'Standard Notes' diff --git a/packages/desktop/app/javascripts/Main/Strings/strings.ts b/packages/desktop/app/javascripts/Main/Strings/strings.ts new file mode 100644 index 00000000000..17d789dbd25 --- /dev/null +++ b/packages/desktop/app/javascripts/Main/Strings/strings.ts @@ -0,0 +1,143 @@ +import { c } from 'ttag' +import { Strings } from './types' + +export function createStrings(): Strings { + return { + appMenu: { + edit: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Edit`, + view: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`View`, + hideMenuBar: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Hide Menu Bar`, + useThemedMenuBar: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Use Themed Menu Bar`, + minimizeToTrayOnClose: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Minimize To Tray On Close`, + backups: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Backups`, + enableAutomaticUpdates: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Enable Automatic Updates`, + automaticUpdatesDisabled: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Automatic Updates Disabled`, + disableAutomaticBackups: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Disable Automatic Backups`, + enableAutomaticBackups: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Enable Automatic Backups`, + emailSupport: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Email Support`, + website: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Website`, + gitHub: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`GitHub`, + discord: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Discord`, + twitter: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Twitter`, + toggleErrorConsole: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Toggle Error Console`, + openDataDirectory: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Open Data Directory`, + clearCacheAndReload: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Clear Cache and Reload`, + speech: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Speech`, + close: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Close`, + minimize: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Minimize`, + zoom: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Zoom`, + bringAllToFront: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Bring All to Front`, + checkForUpdate: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Check for Update`, + checkingForUpdate: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Checking for update…`, + updateAvailable: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`(1) Update Available`, + updates: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Updates`, + releaseNotes: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Release Notes`, + openDownloadLocation: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Open Download Location`, + downloadingUpdate: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Downloading Update…`, + manuallyDownloadUpdate: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Manually Download Update`, + spellcheckerLanguages: c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Spellchecker Languages`, + installPendingUpdate(versionNumber: string) { + return c('B8.MobileDesktopShared.Desktop.Menu.Label').t`Install Pending Update (${versionNumber})` + }, + lastUpdateCheck(date: Date) { + const dateString = date.toLocaleString() + return c('B8.MobileDesktopShared.Desktop.Menu.Info').t`Last checked ${dateString}` + }, + version(number: string) { + return c('B8.MobileDesktopShared.Desktop.Menu.Info').t`Version: ${number}` + }, + yourVersion(number: string) { + return c('B8.MobileDesktopShared.Desktop.Menu.Info').t`Your Version: ${number}` + }, + latestVersion(number: string) { + return c('B8.MobileDesktopShared.Desktop.Menu.Info').t`Latest Version: ${number}` + }, + viewReleaseNotes(versionNumber: string) { + return c('B8.MobileDesktopShared.Desktop.Menu.Label').t`View ${versionNumber} Release Notes` + }, + preferencesChanged: { + title: c('B8.MobileDesktopShared.Desktop.Menu.Title').t`Preference Changed`, + message: c('B8.MobileDesktopShared.Desktop.Menu.Info') + .t`Your menu bar preference has been saved. Please restart the application for the change to take effect.`, + }, + security: { + security: c('B8.MobileDesktopShared.Desktop.Security.Label').t`Security`, + useKeyringtoStorePassword: c('B8.MobileDesktopShared.Desktop.Security.Label') + .t`Use password storage to store password`, + enabledKeyringAccessMessage: c('B8.MobileDesktopShared.Desktop.Security.Info') + .t`Standard Notes will try to use your system's password storage facility to store your password the next time you start it.`, + enabledKeyringQuitNow: c('B8.MobileDesktopShared.Desktop.Security.Action').t`Quit Now`, + enabledKeyringPostpone: c('B8.MobileDesktopShared.Desktop.Security.Action').t`Postpone`, + }, + }, + contextMenu: { + learnSpelling: c('B8.MobileDesktopShared.Desktop.ContextMenu.Label').t`Learn Spelling`, + noSuggestions: c('B8.MobileDesktopShared.Desktop.ContextMenu.Label').t`No Suggestions`, + }, + tray: { + show: c('B8.MobileDesktopShared.Desktop.Tray.Label').t`Show`, + hide: c('B8.MobileDesktopShared.Desktop.Tray.Label').t`Hide`, + quit: c('B8.MobileDesktopShared.Desktop.Tray.Label').t`Quit`, + }, + extensions: { + missingExtension: c('B8.MobileDesktopShared.Desktop.Extensions.Error') + .t`The extension was not found on your system, possibly because it is still downloading. If the extension doesn't load, try uninstalling then reinstalling the extension.`, + unableToLoadExtension: c('B8.MobileDesktopShared.Desktop.Extensions.Error') + .t`Unable to load extension. Please restart the application and try again. If the issue persists, try uninstalling then reinstalling the extension.`, + }, + updates: { + automaticUpdatesEnabled: { + title: c('B8.MobileDesktopShared.Desktop.Updates.Title').t`Automatic Updates Enabled.`, + message: c('B8.MobileDesktopShared.Desktop.Updates.Info') + .t`Automatic updates have been enabled. Please note that this functionality is currently in beta, and that you are advised to periodically check in and ensure you are running the latest version.`, + }, + finishedChecking: { + title: c('B8.MobileDesktopShared.Desktop.Updates.Title').t`Finished checking for updates.`, + error(description: string) { + return c('B8.MobileDesktopShared.Desktop.Updates.Error') + .t`An issue occurred while checking for updates. Please try again.\nIf this issue persists please contact support with the following information: ${description}` + }, + updateAvailable(newVersion: string) { + return c('B8.MobileDesktopShared.Desktop.Updates.Info') + .t`A new update is available (version ${newVersion}). You can wait for the app to update itself, or manually download and install this update.` + }, + noUpdateAvailable(currentVersion: string) { + return c('B8.MobileDesktopShared.Desktop.Updates.Info') + .t`Your version (${currentVersion}) is the latest available version.` + }, + }, + updateReady: { + title: c('B8.MobileDesktopShared.Desktop.Updates.Title').t`Update Ready`, + message(version: string) { + return c('B8.MobileDesktopShared.Desktop.Updates.Info') + .t`A new update (version ${version}) is ready to install.` + }, + quitAndInstall: c('B8.MobileDesktopShared.Desktop.Updates.Action').t`Quit and Install`, + installLater: c('B8.MobileDesktopShared.Desktop.Updates.Action').t`Install Later`, + noRecentBackupMessage: c('B8.MobileDesktopShared.Desktop.Updates.Info') + .t`An update is ready to install, but your backups folder does not appear to contain a recent enough backup. Please download a backup manually before proceeding with the installation.`, + noRecentBackupDetail(lastBackupDate: number | null) { + const downloadInstructions = c('B8.MobileDesktopShared.Desktop.Updates.Info') + .t`You can download a backup from the Account menu in the bottom-left corner of the app.` + const lastAutomaticBackup = + lastBackupDate === null + ? c('B8.MobileDesktopShared.Desktop.Updates.Info').t`Your backups folder is empty.` + : (() => { + const backupDateString = new Date(lastBackupDate).toLocaleString() + return c('B8.MobileDesktopShared.Desktop.Updates.Info') + .t`Your latest automatic backup is from ${backupDateString}.` + })() + return `${downloadInstructions}\n${lastAutomaticBackup}` + }, + noRecentBackupChecbox: c('B8.MobileDesktopShared.Desktop.Updates.Label') + .t`I have downloaded a backup, proceed with installation`, + }, + errorDownloading: { + title: c('B8.MobileDesktopShared.Desktop.Updates.Title').t`Error Downloading`, + message: c('B8.MobileDesktopShared.Desktop.Updates.Error') + .t`An error occurred while trying to download your update file. Please try again.`, + }, + unknownVersionName: c('B8.MobileDesktopShared.Desktop.Updates.Info').t`Unknown`, + }, + } +} diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 556aba4f58c..d3810ea1fee 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -29,7 +29,8 @@ "start": "electron ./app --enable-logging --icon _icon/icon.png", "ava": "rimraf test/data/tmp && ava --serial", "rebuild:keytar": "yarn app/node_modules/keytar build ", - "rebuild:home-server": "electron-rebuild -f -w @standardnotes/home-server -m ./app" + "rebuild:home-server": "electron-rebuild -f -w @standardnotes/home-server -m ./app", + "i18n:extract": "echo 'ttag: extract desktop'; mkdir -p po && ttag extract app/javascripts -o po/template.pot" }, "installConfig": { "hoistingLimits": "workspaces" @@ -51,7 +52,8 @@ "fs-extra": "^11.1.1", "lodash": "^4.17.21", "mime-types": "^2.1.35", - "mobx": "^6.10.2" + "mobx": "^6.10.2", + "ttag": "^1.8.12" }, "devDependencies": { "@babel/core": "*", diff --git a/packages/encryption/package.json b/packages/encryption/package.json index ef5580f12e7..1ecf7500e5c 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -34,6 +34,7 @@ "@standardnotes/responses": "workspace:*", "@standardnotes/sncrypto-common": "workspace:*", "@standardnotes/utils": "workspace:*", - "reflect-metadata": "^0.1.13" + "reflect-metadata": "^0.1.13", + "ttag": "^1.8.12" } } diff --git a/packages/encryption/src/Domain/Keys/Utils/KeyRecoveryStrings.ts b/packages/encryption/src/Domain/Keys/Utils/KeyRecoveryStrings.ts index 0edac61b784..77f5e6d8921 100644 --- a/packages/encryption/src/Domain/Keys/Utils/KeyRecoveryStrings.ts +++ b/packages/encryption/src/Domain/Keys/Utils/KeyRecoveryStrings.ts @@ -1,4 +1,5 @@ import { KeyParamsOrigination } from '@standardnotes/common' +import { c } from 'ttag' import { SNRootKeyParams } from '../RootKey/RootKeyParams' export const KeyRecoveryStrings = { @@ -6,27 +7,49 @@ export const KeyRecoveryStrings = { const dateString = keyParams.createdDate?.toLocaleString() switch (keyParams.origination) { case KeyParamsOrigination.EmailChange: - return `Enter your account password as it was when you changed your email on ${dateString}.` + return c('B5.SecuritySync.Challenge.Info') + .t`Enter your account password as it was when you changed your email on ${dateString}.` case KeyParamsOrigination.PasswordChange: - return `Enter your account password after it was changed on ${dateString}.` + return c('B5.SecuritySync.Challenge.Info').t`Enter your account password after it was changed on ${dateString}.` case KeyParamsOrigination.Registration: - return `Enter your account password as it was when you registered ${dateString}.` + return c('B5.SecuritySync.Challenge.Info') + .t`Enter your account password as it was when you registered ${dateString}.` case KeyParamsOrigination.ProtocolUpgrade: - return `Enter your account password as it was when you upgraded your encryption version on ${dateString}.` + return c('B5.SecuritySync.Challenge.Info') + .t`Enter your account password as it was when you upgraded your encryption version on ${dateString}.` case KeyParamsOrigination.PasscodeChange: - return `Enter your application passcode after it was changed on ${dateString}.` + return c('B5.SecuritySync.Challenge.Info') + .t`Enter your application passcode after it was changed on ${dateString}.` case KeyParamsOrigination.PasscodeCreate: - return `Enter your application passcode as it was when you created it on ${dateString}.` + return c('B5.SecuritySync.Challenge.Info') + .t`Enter your application passcode as it was when you created it on ${dateString}.` default: throw Error('Unhandled KeyParamsOrigination case for KeyRecoveryLoginFlowPrompt') } }, - KeyRecoveryLoginFlowReason: 'Your account password is required to revalidate your session.', - KeyRecoveryLoginFlowInvalidPassword: 'Incorrect credentials entered. Please try again.', - KeyRecoveryRootKeyReplaced: 'Your credentials have successfully been updated.', - KeyRecoveryPasscodeRequiredTitle: 'Passcode Required', - KeyRecoveryPasscodeRequiredText: 'You must enter your passcode in order to save your new credentials.', - KeyRecoveryPasswordRequired: 'Your account password is required to recover an encryption key.', - KeyRecoveryKeyRecovered: 'Your key has successfully been recovered.', - KeyRecoveryUnableToRecover: 'Unable to recover your key with the attempted password. Please try again.', + get KeyRecoveryLoginFlowReason() { + return c('B5.SecuritySync.Challenge.Info').t`Your account password is required to revalidate your session.` + }, + get KeyRecoveryLoginFlowInvalidPassword() { + return c('B5.SecuritySync.Challenge.Error').t`Incorrect credentials entered. Please try again.` + }, + get KeyRecoveryRootKeyReplaced() { + return c('B5.SecuritySync.Challenge.Info').t`Your credentials have successfully been updated.` + }, + get KeyRecoveryPasscodeRequiredTitle() { + return c('B5.SecuritySync.Challenge.Label').t`Passcode Required` + }, + get KeyRecoveryPasscodeRequiredText() { + return c('B5.SecuritySync.Challenge.Info').t`You must enter your passcode in order to save your new credentials.` + }, + get KeyRecoveryPasswordRequired() { + return c('B5.SecuritySync.Challenge.Info').t`Your account password is required to recover an encryption key.` + }, + get KeyRecoveryKeyRecovered() { + return c('B5.SecuritySync.Challenge.Info').t`Your key has successfully been recovered.` + }, + get KeyRecoveryUnableToRecover() { + return c('B5.SecuritySync.Challenge.Error') + .t`Unable to recover your key with the attempted password. Please try again.` + }, } diff --git a/packages/features/package.json b/packages/features/package.json index f7d3982fef1..07bced70b1e 100644 --- a/packages/features/package.json +++ b/packages/features/package.json @@ -27,7 +27,8 @@ "dependencies": { "@standardnotes/common": "^1.50.0", "@standardnotes/domain-core": "^1.40.0", - "reflect-metadata": "^0.1.13" + "reflect-metadata": "^0.1.13", + "ttag": "^1.8.12" }, "devDependencies": { "@types/jest": "^29.2.3", diff --git a/packages/features/src/Domain/Lists/ClientFeatures.ts b/packages/features/src/Domain/Lists/ClientFeatures.ts index 3308a137630..8f96f79b0dc 100644 --- a/packages/features/src/Domain/Lists/ClientFeatures.ts +++ b/packages/features/src/Domain/Lists/ClientFeatures.ts @@ -2,33 +2,35 @@ import { PermissionName } from '../Permission/PermissionName' import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier' import { RoleName } from '@standardnotes/domain-core' import { ClientFeatureDescription } from '../Feature/ClientFeatureDescription' +import { c } from 'ttag' export function clientFeatures(): ClientFeatureDescription[] { return [ { - name: 'Tag Nesting', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Tag Nesting`, availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], identifier: NativeFeatureIdentifier.TYPES.TagNesting, permission_name: PermissionName.TagNesting, - description: 'Organize your tags into folders.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Organize your tags into folders.`, }, { - name: 'Smart Filters', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Smart Filters`, availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], identifier: NativeFeatureIdentifier.TYPES.SmartFilters, permission_name: PermissionName.SmartFilters, - description: 'Create smart filters for viewing notes matching specific criteria.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`Create smart filters for viewing notes matching specific criteria.`, }, { - name: 'Encrypted files', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Encrypted files`, availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], identifier: NativeFeatureIdentifier.TYPES.Files, permission_name: PermissionName.Files, description: '', }, { - name: 'Clipper', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Clipper`, availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], identifier: NativeFeatureIdentifier.TYPES.Clipper, permission_name: PermissionName.Clipper, diff --git a/packages/features/src/Domain/Lists/DeprecatedFeatures.ts b/packages/features/src/Domain/Lists/DeprecatedFeatures.ts index b8d3bb2e7af..a2deaca6402 100644 --- a/packages/features/src/Domain/Lists/DeprecatedFeatures.ts +++ b/packages/features/src/Domain/Lists/DeprecatedFeatures.ts @@ -8,10 +8,11 @@ import { NoteType } from '../Component/NoteType' import { FillIframeEditorDefaults } from './Utilities/FillEditorComponentDefaults' import { ComponentAction } from '../Component/ComponentAction' import { ComponentArea } from '../Component/ComponentArea' +import { c } from 'ttag' export function GetDeprecatedFeatures(): AnyFeatureDescription[] { const code = FillIframeEditorDefaults({ - name: 'Code', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Code`, spellcheckControl: true, identifier: NativeFeatureIdentifier.TYPES.DeprecatedCodeEditor, permission_name: PermissionName.DeprecatedCodeEditor, @@ -20,43 +21,42 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] { interchangeable: true, deprecated: true, index_path: 'index.html', - description: - 'Syntax highlighting and convenient keyboard shortcuts for over 120 programming' + - ' languages. Ideal for code snippets and procedures.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`Syntax highlighting and convenient keyboard shortcuts for over 120 programming languages. Ideal for code snippets and procedures.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/code.jpg', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const plus = FillIframeEditorDefaults({ - name: 'Rich Text', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Rich Text`, note_type: NoteType.RichText, file_type: 'html', identifier: NativeFeatureIdentifier.TYPES.DeprecatedPlusEditor, permission_name: PermissionName.DeprecatedPlusEditor, spellcheckControl: true, deprecated: true, - description: - 'From highlighting to custom font sizes and colors, to tables and lists, this editor is perfect for crafting any document.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`From highlighting to custom font sizes and colors, to tables and lists, this editor is perfect for crafting any document.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/plus-editor.jpg', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const markdown = FillIframeEditorDefaults({ - name: 'Markdown', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Markdown`, identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownProEditor, note_type: NoteType.Markdown, file_type: 'md', permission_name: PermissionName.DeprecatedMarkdownProEditor, spellcheckControl: true, deprecated: true, - description: - 'A fully featured Markdown editor that supports live preview, a styling toolbar, and split pane support.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`A fully featured Markdown editor that supports live preview, a styling toolbar, and split pane support.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/adv-markdown.jpg', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const task = FillIframeEditorDefaults({ - name: 'Checklist', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Checklist`, identifier: NativeFeatureIdentifier.TYPES.DeprecatedTaskEditor, note_type: NoteType.Task, spellcheckControl: true, @@ -64,14 +64,14 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] { interchangeable: false, deprecated: true, permission_name: PermissionName.DeprecatedTaskEditor, - description: - 'A great way to manage short-term and long-term to-do"s. You can mark tasks as completed, change their order, and edit the text naturally in place.', + description: c('B7.FilesSubscriptionHelp.Subscription.Status') + .t`A great way to manage short-term and long-term to-do"s. You can mark tasks as completed, change their order, and edit the text naturally in place.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/task-editor.jpg', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const bold: EditorFeatureDescription = FillIframeEditorDefaults({ - name: 'Alternative Rich Text', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Alternative Rich Text`, identifier: NativeFeatureIdentifier.TYPES.DeprecatedBoldEditor, note_type: NoteType.RichText, file_type: 'html', @@ -92,40 +92,41 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] { spellcheckControl: true, deprecated: true, permission_name: PermissionName.BoldEditor, - description: 'A simple and peaceful rich editor that helps you write and think clearly.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`A simple and peaceful rich editor that helps you write and think clearly.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/bold.jpg', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const markdownBasic: EditorFeatureDescription = FillIframeEditorDefaults({ - name: 'Basic Markdown', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Basic Markdown`, identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownBasicEditor, note_type: NoteType.Markdown, spellcheckControl: true, file_type: 'md', deprecated: true, permission_name: PermissionName.MarkdownBasicEditor, - description: 'A Markdown editor with dynamic split-pane preview.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info').t`A Markdown editor with dynamic split-pane preview.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/simple-markdown.jpg', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const markdownAlt: EditorFeatureDescription = FillIframeEditorDefaults({ - name: 'Markdown Alternative', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Markdown Alternative`, identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownVisualEditor, note_type: NoteType.Markdown, file_type: 'md', deprecated: true, permission_name: PermissionName.MarkdownVisualEditor, spellcheckControl: true, - description: - 'A WYSIWYG-style Markdown editor that renders Markdown in preview-mode while you type without displaying any syntax.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`A WYSIWYG-style Markdown editor that renders Markdown in preview-mode while you type without displaying any syntax.`, index_path: 'build/index.html', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const markdownMinimist: EditorFeatureDescription = FillIframeEditorDefaults({ - name: 'Minimal Markdown', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Minimal Markdown`, identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownMinimistEditor, note_type: NoteType.Markdown, file_type: 'md', @@ -133,13 +134,14 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] { permission_name: PermissionName.MarkdownMinimistEditor, spellcheckControl: true, deprecated: true, - description: 'A minimal Markdown editor with live rendering and in-text search via Ctrl/Cmd + F', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`A minimal Markdown editor with live rendering and in-text search via Ctrl/Cmd + F`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/min-markdown.jpg', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const markdownMath: EditorFeatureDescription = FillIframeEditorDefaults({ - name: 'Markdown with Math', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Markdown with Math`, identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownMathEditor, spellcheckControl: true, permission_name: PermissionName.MarkdownMathEditor, @@ -147,13 +149,14 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] { file_type: 'md', deprecated: true, index_path: 'index.html', - description: 'A beautiful split-pane Markdown editor with synced-scroll, LaTeX support, and colorful syntax.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`A beautiful split-pane Markdown editor with synced-scroll, LaTeX support, and colorful syntax.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/fancy-markdown.jpg', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const filesafe: IframeComponentFeatureDescription = FillIframeEditorDefaults({ - name: 'FileSafe', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`FileSafe`, identifier: NativeFeatureIdentifier.TYPES.DeprecatedFileSafe, component_permissions: [ { @@ -172,8 +175,8 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] { permission_name: PermissionName.ComponentFilesafe, area: ComponentArea.EditorStack, deprecated: true, - description: - 'Encrypted attachments for your notes using your Dropbox, Google Drive, or WebDAV server. Limited to 50MB per file.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`Encrypted attachments for your notes using your Dropbox, Google Drive, or WebDAV server. Limited to 50MB per file.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/FileSafe-banner.png', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) diff --git a/packages/features/src/Domain/Lists/ExperimentalFeatures.ts b/packages/features/src/Domain/Lists/ExperimentalFeatures.ts index ba523524c33..57491a96da3 100644 --- a/packages/features/src/Domain/Lists/ExperimentalFeatures.ts +++ b/packages/features/src/Domain/Lists/ExperimentalFeatures.ts @@ -2,12 +2,14 @@ import { RoleName } from '@standardnotes/domain-core' import { AnyFeatureDescription } from '../Feature/AnyFeatureDescription' import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier' import { PermissionName } from '../Permission/PermissionName' +import { c } from 'ttag' export function experimentalFeatures(): AnyFeatureDescription[] { return [ { - name: 'Private vaults', - description: 'Private vaults allow you to store notes, files and tags into separate, encrypted vaults.', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Private vaults`, + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`Private vaults allow you to store notes, files and tags into separate, encrypted vaults.`, availableInRoles: [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], identifier: NativeFeatureIdentifier.TYPES.Vaults, permission_name: PermissionName.Vaults, diff --git a/packages/features/src/Domain/Lists/IframeEditors.ts b/packages/features/src/Domain/Lists/IframeEditors.ts index 08dc43b5538..da9c4a0afd9 100644 --- a/packages/features/src/Domain/Lists/IframeEditors.ts +++ b/packages/features/src/Domain/Lists/IframeEditors.ts @@ -4,30 +4,31 @@ import { NoteType } from '../Component/NoteType' import { FillIframeEditorDefaults } from './Utilities/FillEditorComponentDefaults' import { RoleName } from '@standardnotes/domain-core' import { IframeComponentFeatureDescription } from '../Feature/IframeComponentFeatureDescription' +import { c } from 'ttag' export function IframeEditors(): IframeComponentFeatureDescription[] { const tokenvault = FillIframeEditorDefaults({ - name: 'Authenticator', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Authenticator`, note_type: NoteType.Authentication, file_type: 'json', interchangeable: false, identifier: NativeFeatureIdentifier.TYPES.TokenVaultEditor, permission_name: PermissionName.TokenVaultEditor, - description: - 'Encrypt and protect your 2FA secrets for all your internet accounts. Authenticator handles your 2FA secrets so that you never lose them again, or have to start over when you get a new device.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`Encrypt and protect your 2FA secrets for all your internet accounts. Authenticator handles your 2FA secrets so that you never lose them again, or have to start over when you get a new device.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/token-vault.png', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) const spreadsheets = FillIframeEditorDefaults({ - name: 'Spreadsheet', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Spreadsheet`, identifier: NativeFeatureIdentifier.TYPES.SheetsEditor, note_type: NoteType.Spreadsheet, file_type: 'json', interchangeable: false, permission_name: PermissionName.SheetsEditor, - description: - 'A powerful spreadsheet editor with formatting and formula support. Not recommended for large data sets, as encryption of such data may decrease editor performance.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`A powerful spreadsheet editor with formatting and formula support. Not recommended for large data sets, as encryption of such data may decrease editor performance.`, thumbnail_url: 'https://assets.standardnotes.com/screenshots/models/editors/spreadsheets.png', availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }) diff --git a/packages/features/src/Domain/Lists/NativeEditors.ts b/packages/features/src/Domain/Lists/NativeEditors.ts index 71620bc398d..333404445ac 100644 --- a/packages/features/src/Domain/Lists/NativeEditors.ts +++ b/packages/features/src/Domain/Lists/NativeEditors.ts @@ -3,11 +3,12 @@ import { NoteType } from '../Component/NoteType' import { EditorFeatureDescription } from '../Feature/EditorFeatureDescription' import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier' import { PermissionName } from '../Permission/PermissionName' +import { c } from 'ttag' export function nativeEditors(): EditorFeatureDescription[] { return [ { - name: 'Super', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Super`, note_type: NoteType.Super, identifier: NativeFeatureIdentifier.TYPES.SuperEditor, spellcheckControl: true, @@ -15,11 +16,11 @@ export function nativeEditors(): EditorFeatureDescription[] { interchangeable: false, availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], permission_name: PermissionName.SuperEditor, - description: - 'The best way to edit notes. Type / to bring up the block selection menu, or @ to embed images or link other tags and notes. Type - then space to start a list, or [] then space to start a checklist. Drag and drop an image or file to embed it in your note. Cmd/Ctrl + F to bring up search and replace.', + description: c('B7.FilesSubscriptionHelp.Subscription.Info') + .t`The best way to edit notes. Type / to bring up the block selection menu, or @ to embed images or link other tags and notes. Type - then space to start a list, or [] then space to start a checklist. Drag and drop an image or file to embed it in your note. Cmd/Ctrl + F to bring up search and replace.`, }, { - name: 'Plain Text', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Plain Text`, note_type: NoteType.Plain, spellcheckControl: true, file_type: 'txt', diff --git a/packages/features/src/Domain/Lists/ServerFeatures.ts b/packages/features/src/Domain/Lists/ServerFeatures.ts index bdf978a0a87..54b5fb21c61 100644 --- a/packages/features/src/Domain/Lists/ServerFeatures.ts +++ b/packages/features/src/Domain/Lists/ServerFeatures.ts @@ -2,71 +2,72 @@ import { ServerFeatureDescription } from '../Feature/ServerFeatureDescription' import { PermissionName } from '../Permission/PermissionName' import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier' import { RoleName } from '@standardnotes/domain-core' +import { c } from 'ttag' export function serverFeatures(): ServerFeatureDescription[] { return [ { - name: 'Two factor authentication', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Two factor authentication`, identifier: NativeFeatureIdentifier.TYPES.TwoFactorAuth, permission_name: PermissionName.TwoFactorAuth, availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }, { - name: 'U2F authentication', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`U2F authentication`, identifier: NativeFeatureIdentifier.TYPES.UniversalSecondFactor, permission_name: PermissionName.UniversalSecondFactor, availableInRoles: [RoleName.NAMES.ProUser], }, { - name: 'Unlimited note history', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Unlimited note history`, identifier: NativeFeatureIdentifier.TYPES.NoteHistoryUnlimited, permission_name: PermissionName.NoteHistoryUnlimited, availableInRoles: [RoleName.NAMES.ProUser], }, { - name: '365 days note history', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`365 days note history`, identifier: NativeFeatureIdentifier.TYPES.NoteHistory365Days, permission_name: PermissionName.NoteHistory365Days, availableInRoles: [RoleName.NAMES.PlusUser], }, { - name: 'Email backups', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Email backups`, identifier: NativeFeatureIdentifier.TYPES.DailyEmailBackup, permission_name: PermissionName.DailyEmailBackup, availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }, { - name: 'Sign-in email alerts', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Sign-in email alerts`, identifier: NativeFeatureIdentifier.TYPES.SignInAlerts, permission_name: PermissionName.SignInAlerts, availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }, { - name: 'Files maximum storage tier', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Files maximum storage tier`, identifier: NativeFeatureIdentifier.TYPES.FilesMaximumStorageTier, permission_name: PermissionName.FilesMaximumStorageTier, availableInRoles: [RoleName.NAMES.ProUser], }, { - name: 'Files low storage tier', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Files low storage tier`, identifier: NativeFeatureIdentifier.TYPES.FilesLowStorageTier, permission_name: PermissionName.FilesLowStorageTier, availableInRoles: [RoleName.NAMES.PlusUser], }, { - name: 'Files medium storage tier', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Files medium storage tier`, identifier: NativeFeatureIdentifier.TYPES.SubscriptionSharing, permission_name: PermissionName.SubscriptionSharing, availableInRoles: [RoleName.NAMES.ProUser], }, { - name: 'Listed Custom Domain', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Listed Custom Domain`, identifier: NativeFeatureIdentifier.TYPES.ListedCustomDomain, permission_name: PermissionName.ListedCustomDomain, availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], }, { - name: 'Shared Vaults', + name: c('B7.FilesSubscriptionHelp.Subscription.Info').t`Shared Vaults`, identifier: NativeFeatureIdentifier.TYPES.SharedVaults, permission_name: PermissionName.SharedVaults, availableInRoles: [RoleName.NAMES.InternalTeamUser], diff --git a/packages/features/src/Domain/Lists/Themes.ts b/packages/features/src/Domain/Lists/Themes.ts index 90b7fc92adb..15580c4962d 100644 --- a/packages/features/src/Domain/Lists/Themes.ts +++ b/packages/features/src/Domain/Lists/Themes.ts @@ -3,10 +3,11 @@ import { PermissionName } from '../Permission/PermissionName' import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier' import { FillThemeComponentDefaults } from './Utilities/FillThemeComponentDefaults' import { RoleName } from '@standardnotes/domain-core' +import { c } from 'ttag' export function themes(): ThemeFeatureDescription[] { const midnight: ThemeFeatureDescription = FillThemeComponentDefaults({ - name: 'Midnight', + name: c('B6.Preferences.Appearance.Label').t`Midnight`, identifier: NativeFeatureIdentifier.TYPES.MidnightTheme, permission_name: PermissionName.MidnightTheme, isDark: true, @@ -21,7 +22,7 @@ export function themes(): ThemeFeatureDescription[] { const futura: ThemeFeatureDescription = FillThemeComponentDefaults({ availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], - name: 'Futura', + name: c('B6.Preferences.Appearance.Label').t`Futura`, identifier: NativeFeatureIdentifier.TYPES.FuturaTheme, permission_name: PermissionName.FuturaTheme, isDark: true, @@ -35,7 +36,7 @@ export function themes(): ThemeFeatureDescription[] { const solarizedDark: ThemeFeatureDescription = FillThemeComponentDefaults({ availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], - name: 'Solarized Dark', + name: c('B6.Preferences.Appearance.Label').t`Solarized Dark`, identifier: NativeFeatureIdentifier.TYPES.SolarizedDarkTheme, permission_name: PermissionName.SolarizedDarkTheme, isDark: true, @@ -49,7 +50,7 @@ export function themes(): ThemeFeatureDescription[] { const autobiography: ThemeFeatureDescription = FillThemeComponentDefaults({ availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], - name: 'Autobiography', + name: c('B6.Preferences.Appearance.Label').t`Autobiography`, identifier: NativeFeatureIdentifier.TYPES.AutobiographyTheme, permission_name: PermissionName.AutobiographyTheme, dock_icon: { @@ -62,7 +63,7 @@ export function themes(): ThemeFeatureDescription[] { const dark: ThemeFeatureDescription = FillThemeComponentDefaults({ availableInRoles: [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], - name: 'Dark', + name: c('B6.Preferences.Appearance.Label').t`Dark`, identifier: NativeFeatureIdentifier.TYPES.DarkTheme, permission_name: PermissionName.FocusedTheme, clientControlled: true, @@ -77,7 +78,7 @@ export function themes(): ThemeFeatureDescription[] { const titanium: ThemeFeatureDescription = FillThemeComponentDefaults({ availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], - name: 'Titanium', + name: c('B6.Preferences.Appearance.Label').t`Titanium`, identifier: NativeFeatureIdentifier.TYPES.TitaniumTheme, permission_name: PermissionName.TitaniumTheme, dock_icon: { @@ -90,7 +91,7 @@ export function themes(): ThemeFeatureDescription[] { const dynamic: ThemeFeatureDescription = FillThemeComponentDefaults({ availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], - name: 'Dynamic Panels', + name: c('B6.Preferences.Appearance.Label').t`Dynamic Panels`, identifier: NativeFeatureIdentifier.TYPES.DynamicTheme, permission_name: PermissionName.ThemeDynamic, layerable: true, @@ -99,7 +100,7 @@ export function themes(): ThemeFeatureDescription[] { const proton: ThemeFeatureDescription = FillThemeComponentDefaults({ availableInRoles: [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser], - name: 'Carbon', + name: c('B6.Preferences.Appearance.Label').t`Carbon`, identifier: NativeFeatureIdentifier.TYPES.ProtonTheme, permission_name: PermissionName.ProtonTheme, dock_icon: { diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 4b37437abe2..870a72a3f7a 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -22,7 +22,8 @@ "start": "react-native start", "tsc": "tsc --noEmit", "upgrade:snjs": "ncu -u '@standardnotes/*'", - "bundle:web": "mkdir -p html/Web.bundle/src/web-src/ && cp -r ../web/dist/. html/Web.bundle/src/web-src/" + "bundle:web": "mkdir -p html/Web.bundle/src/web-src/ && cp -r ../web/dist/. html/Web.bundle/src/web-src/", + "i18n:extract": "echo 'ttag: extract mobile'; mkdir -p po && ttag extract src -o po/template.pot" }, "installConfig": { "hoistingLimits": "workspaces" @@ -77,6 +78,7 @@ "dependencies": { "@notifee/react-native": "^9.1.8", "react-native-safe-area-context": "^5.5.1", - "react-native-store-review": "^0.4.3" + "react-native-store-review": "^0.4.3", + "ttag": "^1.8.12" } } diff --git a/packages/mobile/src/Lib/Database/showLoadFailForItemIds.ts b/packages/mobile/src/Lib/Database/showLoadFailForItemIds.ts index 6406d2177fb..77cb6ff2da6 100644 --- a/packages/mobile/src/Lib/Database/showLoadFailForItemIds.ts +++ b/packages/mobile/src/Lib/Database/showLoadFailForItemIds.ts @@ -1,16 +1,10 @@ import { Alert } from 'react-native' +import { c } from 'ttag' export const showLoadFailForItemIds = (failedItemIds: string[]) => { - let text = - 'The following items could not be loaded. This may happen if you are in low-memory conditions, or if the note is very large in size. We recommend breaking up large notes into smaller chunks using the desktop or web app.\n\nItems:\n' - let index = 0 - text += failedItemIds.map((id) => { - let result = id - if (index !== failedItemIds.length - 1) { - result += '\n' - } - index++ - return result - }) - Alert.alert('Unable to load item(s)', text) + const items = failedItemIds.join('\n') + const text = c('B8.MobileDesktopShared.Mobile.Database.Info') + .t`The following items could not be loaded. This may happen if you are in low-memory conditions, or if the note is very large in size. We recommend breaking up large notes into smaller chunks using the desktop or web app.\n\nItems:\n${items}` + + Alert.alert(c('B8.MobileDesktopShared.Mobile.Database.Title').t`Unable to load item(s)`, text) } diff --git a/packages/mobile/src/Lib/MobileDevice.ts b/packages/mobile/src/Lib/MobileDevice.ts index f5bad44a653..29d9c75a23f 100644 --- a/packages/mobile/src/Lib/MobileDevice.ts +++ b/packages/mobile/src/Lib/MobileDevice.ts @@ -54,6 +54,7 @@ import { isLegacyIdentifier } from './Database/LegacyIdentifier' import { LegacyKeyValueStore } from './Database/LegacyKeyValueStore' import Keychain from './Keychain' import notifee, { AuthorizationStatus, Notification, NotificationSettings } from '@notifee/react-native' +import { c } from 'ttag' export type BiometricsType = 'Fingerprint' | 'Face ID' | 'Biometrics' | 'Touch ID' @@ -93,7 +94,7 @@ export class MobileDevice implements MobileDeviceInterface { await notifee.createChannel({ id: 'files', - name: 'File Upload/Download', + name: c('B8.MobileDesktopShared.Mobile.Notifications.Label').t`File Upload/Download`, }) const didAskForPermission = await this.keyValueStore.getValue('didAskForNotificationPermission') @@ -265,7 +266,7 @@ export class MobileDevice implements MobileDeviceInterface { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore ts type does not exist for deviceCredentialAllowed deviceCredentialAllowed: true, - description: 'Biometrics are required to access your notes.', + description: c('B8.MobileDesktopShared.Mobile.Device.Info').t`Biometrics are required to access your notes.`, }) .then(() => { FingerprintScanner.release() @@ -274,9 +275,15 @@ export class MobileDevice implements MobileDeviceInterface { .catch((error) => { FingerprintScanner.release() if (error.name === 'DeviceLocked') { - Alert.alert('Unsuccessful', 'Authentication failed. Wait 30 seconds to try again.') + Alert.alert( + c('B8.MobileDesktopShared.Mobile.Device.Title').t`Unsuccessful`, + c('B8.MobileDesktopShared.Mobile.Device.Error').t`Authentication failed. Wait 30 seconds to try again.`, + ) } else { - Alert.alert('Unsuccessful', 'Authentication failed. Tap to try again.') + Alert.alert( + c('B8.MobileDesktopShared.Mobile.Device.Title').t`Unsuccessful`, + c('B8.MobileDesktopShared.Mobile.Device.Error').t`Authentication failed. Tap to try again.`, + ) } resolve(false) }) @@ -284,7 +291,7 @@ export class MobileDevice implements MobileDeviceInterface { // iOS FingerprintScanner.authenticate({ fallbackEnabled: true, - description: 'This is required to access your notes.', + description: c('B8.MobileDesktopShared.Mobile.Device.Info').t`This is required to access your notes.`, }) .then(() => { FingerprintScanner.release() @@ -294,9 +301,12 @@ export class MobileDevice implements MobileDeviceInterface { FingerprintScanner.release() if (error_1.name !== 'SystemCancel') { if (error_1.name !== 'UserCancel') { - Alert.alert('Unsuccessful') + Alert.alert(c('B8.MobileDesktopShared.Mobile.Device.Title').t`Unsuccessful`) } else { - Alert.alert('Unsuccessful', 'Authentication failed. Tap to try again.') + Alert.alert( + c('B8.MobileDesktopShared.Mobile.Device.Title').t`Unsuccessful`, + c('B8.MobileDesktopShared.Mobile.Device.Error').t`Authentication failed. Tap to try again.`, + ) } } resolve(false) @@ -376,7 +386,10 @@ export class MobileDevice implements MobileDeviceInterface { openUrl(url: string) { const showAlert = () => { - Alert.alert('Unable to Open', `Unable to open URL ${url}.`) + Alert.alert( + c('B8.MobileDesktopShared.Mobile.Device.Title').t`Unable to Open`, + c('B8.MobileDesktopShared.Mobile.Device.Error').t`Unable to open URL ${url}.`, + ) } Linking.canOpenURL(url) @@ -549,17 +562,17 @@ export class MobileDevice implements MobileDeviceInterface { } Alert.alert( - 'Close app', - 'Do you want to close the app?', + c('B8.MobileDesktopShared.Mobile.Device.Title').t`Close app`, + c('B8.MobileDesktopShared.Mobile.Device.Confirmation').t`Do you want to close the app?`, [ { - text: 'Cancel', + text: c('B8.MobileDesktopShared.Mobile.Device.Label').t`Cancel`, style: 'cancel', // eslint-disable-next-line @typescript-eslint/no-empty-function onPress: async () => {}, }, { - text: 'Close', + text: c('B8.MobileDesktopShared.Mobile.Device.Action').t`Close`, style: 'destructive', onPress: async () => { SNReactNative.exitApp() diff --git a/packages/mobile/src/MobileWebAppContainer.tsx b/packages/mobile/src/MobileWebAppContainer.tsx index c36bcac19d5..25560ce0d6f 100644 --- a/packages/mobile/src/MobileWebAppContainer.tsx +++ b/packages/mobile/src/MobileWebAppContainer.tsx @@ -16,6 +16,7 @@ import { ReceivedSharedItemsHandler } from './ReceivedSharedItemsHandler' import { ReviewService } from './ReviewService' import notifee, { EventType } from '@notifee/react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' +import { c } from 'ttag' const LoggingEnabled = IsDev @@ -437,7 +438,7 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo marginBottom: 20, }} > - Could not load app + {c('B8.MobileDesktopShared.Mobile.WebView.Title').t`Could not load app`} vo textAlign: 'center', }} > - Please make sure your Android System Webview is updated to the latest version + {c('B8.MobileDesktopShared.Mobile.WebView.Info') + .t`Please make sure your Android System Webview is updated to the latest version`} diff --git a/packages/web/src/javascripts/Components/ChallengeModal/ChallengeModal.tsx b/packages/web/src/javascripts/Components/ChallengeModal/ChallengeModal.tsx index a2ab336e9ea..cf504b6002a 100644 --- a/packages/web/src/javascripts/Components/ChallengeModal/ChallengeModal.tsx +++ b/packages/web/src/javascripts/Components/ChallengeModal/ChallengeModal.tsx @@ -1,4 +1,5 @@ import { WebApplication } from '@/Application/WebApplication' +import { c } from 'ttag' import { ButtonType, Challenge, @@ -245,14 +246,14 @@ const ChallengeModal: FunctionComponent = ({ application, mainApplication )} > } customFooter={<>} disableCustomHeader={isMobileScreen} actions={[ { - label: 'Cancel', + label: c('B5.SecuritySync.Challenge.Label').t`Cancel`, onClick: cancelChallenge, type: 'primary', hidden: !challenge.cancelable, @@ -263,7 +264,7 @@ const ChallengeModal: FunctionComponent = ({ application, mainApplication {challenge.cancelable && ( )} {shouldShowForgotPasscode && ( @@ -312,9 +315,10 @@ const ChallengeModal: FunctionComponent = ({ application, mainApplication onClick={() => { application.alerts .confirm( - 'If you forgot your local passcode, your only option is to clear your local data from this device and sign back in to your account.', - 'Forgot passcode?', - 'Delete local data', + c('B5.SecuritySync.Passcode.Info') + .t`If you forgot your local passcode, your only option is to clear your local data from this device and sign back in to your account.`, + c('B5.SecuritySync.Passcode.Title').t`Forgot passcode?`, + c('B5.SecuritySync.Passcode.Action').t`Delete local data`, ButtonType.Danger, ) .then((shouldDeleteLocalData) => { @@ -326,7 +330,7 @@ const ChallengeModal: FunctionComponent = ({ application, mainApplication }} > - Forgot passcode? + {c('B5.SecuritySync.Passcode.Title').t`Forgot passcode?`} )} {shouldShowWorkspaceSwitcher && } diff --git a/packages/web/src/javascripts/Components/ChallengeModal/ChallengePrompt.tsx b/packages/web/src/javascripts/Components/ChallengeModal/ChallengePrompt.tsx index 14d2ae48657..8d87a544da2 100644 --- a/packages/web/src/javascripts/Components/ChallengeModal/ChallengePrompt.tsx +++ b/packages/web/src/javascripts/Components/ChallengeModal/ChallengePrompt.tsx @@ -1,3 +1,4 @@ +import { c } from 'ttag' import { ChallengePrompt, ChallengeValidation, @@ -102,7 +103,8 @@ const ChallengeModalPrompt: FunctionComponent = ({
{prompt.validation === ChallengeValidation.ProtectionSessionDuration ? (
-
Allow protected access for
+
{c('B5.SecuritySync.Challenge.Label') + .t`Allow protected access for`}
{ProtectionSessionDurations.map((option) => { const selected = option.valueInSeconds === values[prompt.id].value @@ -164,7 +166,11 @@ const ChallengeModalPrompt: FunctionComponent = ({ onChange={(value) => onValueChange(value, prompt)} /> )} - {isInvalid &&
Invalid authentication, please try again.
} + {isInvalid && ( +
+ {c('B5.SecuritySync.Challenge.Error').t`Invalid authentication, please try again.`} +
+ )}
) } diff --git a/packages/web/src/javascripts/Components/ChallengeModal/LockscreenWorkspaceSwitcher.tsx b/packages/web/src/javascripts/Components/ChallengeModal/LockscreenWorkspaceSwitcher.tsx index e12dabf72f3..82789869533 100644 --- a/packages/web/src/javascripts/Components/ChallengeModal/LockscreenWorkspaceSwitcher.tsx +++ b/packages/web/src/javascripts/Components/ChallengeModal/LockscreenWorkspaceSwitcher.tsx @@ -1,5 +1,6 @@ import { WebApplicationGroup } from '@/Application/WebApplicationGroup' import { FunctionComponent, useCallback, useRef, useState } from 'react' +import { c } from 'ttag' import WorkspaceSwitcherMenu from '@/Components/AccountMenu/WorkspaceSwitcher/WorkspaceSwitcherMenu' import Button from '@/Components/Button/Button' import Icon from '@/Components/Icon/Icon' @@ -22,10 +23,10 @@ const LockscreenWorkspaceSwitcher: FunctionComponent = ({ mainApplication
- Obtained Device Response + {c('B5.SecuritySync.Challenge.Info').t`Obtained Device Response`} ) : ( - 'Authenticate Device' + c('B5.SecuritySync.Challenge.Action').t`Authenticate Device` )}
diff --git a/packages/web/src/javascripts/Components/ChallengeModal/U2FPromptIframeContainer.tsx b/packages/web/src/javascripts/Components/ChallengeModal/U2FPromptIframeContainer.tsx index 549dd2534a2..c8bf85fe96f 100644 --- a/packages/web/src/javascripts/Components/ChallengeModal/U2FPromptIframeContainer.tsx +++ b/packages/web/src/javascripts/Components/ChallengeModal/U2FPromptIframeContainer.tsx @@ -1,6 +1,7 @@ import { log, LoggingDomain } from '@/Logging' import { isDev } from '@/Utils' import { useEffect, useRef } from 'react' +import { c } from 'ttag' type Props = { contextData?: Record @@ -56,7 +57,7 @@ const U2FPromptIframeContainer = ({ contextData, onResponse, apiHost }: Props) = ref={iframeRef} src={U2F_IFRAME_ORIGIN} className="h-40 w-full" - title="U2F" + title={c('B5.SecuritySync.U2F.Label').t`U2F`} allow="publickey-credentials-get" id="u2f" /> diff --git a/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorButton.tsx b/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorButton.tsx index 004a035605f..f25244fc873 100644 --- a/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorButton.tsx +++ b/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorButton.tsx @@ -1,4 +1,5 @@ import { observer } from 'mobx-react-lite' +import { c } from 'ttag' import { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react' import ChangeEditorMenu from './ChangeEditorMenu' import Popover from '../Popover/Popover' @@ -58,7 +59,7 @@ const ChangeEditorButton: FunctionComponent = ({ noteViewController, onCl return application.commands.addWithShortcut( CHANGE_EDITOR_COMMAND, 'Current note', - 'Change note type', + c('B4.Notes.EditingUI.Action').t`Change note type`, () => { void toggleMenu() }, @@ -71,17 +72,19 @@ const ChangeEditorButton: FunctionComponent = ({ noteViewController, onCl [application], ) + const shortcutLabel = shortcut && keyboardStringForShortcut(shortcut) + return (
= ({ } if (note.locked) { - application.alerts.alert(STRING_EDIT_LOCKED_ATTEMPT).catch(console.error) + application.alerts.alert(STRING_EDIT_LOCKED_ATTEMPT()).catch(console.error) return } @@ -252,19 +253,20 @@ const ChangeEditorMenu: FunctionComponent = ({ return ( <> - +
-

Choose a note type

+

{c('B4.Notes.EditingUI.Label').t`Choose a note type`}

{unableToFindEditor && (

- Unable to find system editor for this note. Select Manage Plugins to reinstall this editor. + {c('B4.Notes.EditingUI.Error') + .t`Unable to find system editor for this note. Select Manage Plugins to reinstall this editor.`}

)}
@@ -295,14 +297,14 @@ const ChangeEditorMenu: FunctionComponent = ({ {menuItem.uiFeature.displayName} {menuItem.isLabs && ( - Labs + {c('B4.Notes.EditingUI.Label').t`Labs`} )} {menuItem.uiFeature.featureIdentifier === NativeFeatureIdentifier.TYPES.SuperEditor && !isSelected(menuItem) && recommendSuper && ( - Recommended + {c('B4.Notes.EditingUI.Label').t`Recommended`} )}
diff --git a/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorMultipleMenu.tsx b/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorMultipleMenu.tsx index 115e2c4e556..a75cd0df35d 100644 --- a/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorMultipleMenu.tsx +++ b/packages/web/src/javascripts/Components/ChangeEditor/ChangeEditorMultipleMenu.tsx @@ -12,6 +12,7 @@ import { NativeFeatureIdentifier, } from '@standardnotes/snjs' import { useCallback, useMemo, useState } from 'react' +import { c } from 'ttag' import Icon from '../Icon/Icon' import { PremiumFeatureIconName, PremiumFeatureIconClass } from '../Icon/PremiumFeatureIcon' import Menu from '../Menu/Menu' @@ -71,7 +72,7 @@ const ChangeEditorMultipleMenu = ({ application, notes, setDisableClickOutside } } if (hasSelectedLockedNotes) { - void application.alerts.alert(STRING_EDIT_LOCKED_ATTEMPT) + void application.alerts.alert(STRING_EDIT_LOCKED_ATTEMPT()) return } @@ -138,7 +139,7 @@ const ChangeEditorMultipleMenu = ({ application, notes, setDisableClickOutside } return ( <> - + {groupsWithItems.map((group) => ( {group.items.map((item) => { @@ -157,7 +158,7 @@ const ChangeEditorMultipleMenu = ({ application, notes, setDisableClickOutside } {item.uiFeature.displayName} {item.isLabs && ( - Labs + {c('B4.Notes.EditingUI.Label').t`Labs`} )}
diff --git a/packages/web/src/javascripts/Components/ChangeEditor/ChangeMultipleButton.tsx b/packages/web/src/javascripts/Components/ChangeEditor/ChangeMultipleButton.tsx index fe47c31c31a..46e4b4eb16e 100644 --- a/packages/web/src/javascripts/Components/ChangeEditor/ChangeMultipleButton.tsx +++ b/packages/web/src/javascripts/Components/ChangeEditor/ChangeMultipleButton.tsx @@ -1,4 +1,5 @@ import { WebApplication } from '@/Application/WebApplication' +import { c } from 'ttag' import { NotesController } from '@/Controllers/NotesController/NotesController' import { useRef, useState } from 'react' import RoundIconButton from '../Button/RoundIconButton' @@ -18,9 +19,14 @@ const ChangeMultipleButton = ({ application, notesController }: Props) => { return ( <> - + { if ( await confirmDialog({ - text: 'Are you sure you want to discard this clip?', + text: c('B4.Notes.EditingUI.Confirmation').t`Are you sure you want to discard this clip?`, confirmButtonText: 'Discard', confirmButtonStyle: 'danger', }) @@ -93,7 +94,7 @@ const ClippedNoteView = ({ {!isFirefoxPopup && ( )} diff --git a/packages/web/src/javascripts/Components/ClipperView/ClipperView.tsx b/packages/web/src/javascripts/Components/ClipperView/ClipperView.tsx index de82d43322b..d110d7f123c 100644 --- a/packages/web/src/javascripts/Components/ClipperView/ClipperView.tsx +++ b/packages/web/src/javascripts/Components/ClipperView/ClipperView.tsx @@ -24,6 +24,7 @@ import { classNames, } from '@standardnotes/snjs' import { addToast, ToastType } from '@standardnotes/toast' +import { c } from 'ttag' import { getSuperJSONFromClipPayload } from './getSuperJSONFromClipHTML' import ClippedNoteView from './ClippedNoteView' import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/PremiumFeatureIcon' @@ -38,6 +39,8 @@ import StyledTooltip from '../StyledTooltip/StyledTooltip' import MenuSwitchButtonItem from '../Menu/MenuSwitchButtonItem' import Spinner from '../Spinner/Spinner' +const jtString = (value: unknown): string => (Array.isArray(value) ? value.join('') : String(value)) + const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGroup }) => { const application = useApplication() @@ -137,11 +140,11 @@ const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGro const showSignOutConfirmation = useCallback(async () => { if ( await confirmDialog({ - title: 'Sign Out', - text: 'Are you sure you want to sign out?', - confirmButtonText: 'Sign Out', + title: c('B1.Account.Session.Title').t`Sign Out`, + text: c('B1.Account.Session.Info').t`Are you sure you want to sign out?`, + confirmButtonText: c('B1.Account.Session.Action').t`Sign Out`, confirmButtonStyle: 'danger', - cancelButtonText: 'Cancel', + cancelButtonText: c('B1.Account.Session.Action').t`Cancel`, }) ) { await application.user.signOut() @@ -205,7 +208,7 @@ const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGro if (!clipPayload.content) { addToast({ type: ToastType.Error, - message: 'No content to clip', + message: c('B7.FilesSubscriptionHelp.Help.Error').t`No content to clip`, }) return } @@ -245,7 +248,7 @@ const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGro addToast({ type: ToastType.Success, - message: 'Note clipped successfully', + message: c('B7.FilesSubscriptionHelp.Help.Info').t`Note clipped successfully`, }) const syncRequest = await application.sync.getRawSyncRequestForExternalUse([insertedNote]) @@ -282,6 +285,10 @@ const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGro }, [application, hasSubscription]) if (user && !isEntitledToExtension) { + const webClipperLabel = ( + {c('B7.FilesSubscriptionHelp.Subscription.Label').t`Web Clipper`} + ) + return (
-
Enable Advanced Features
+
{c('B7.FilesSubscriptionHelp.Subscription.Title') + .t`Enable Advanced Features`}
- To take advantage of Web Clipper and other advanced features, upgrade - your current plan. + {jtString( + c('B7.FilesSubscriptionHelp.Subscription.Info') + .jt`To take advantage of ${webClipperLabel} and other advanced features, upgrade your current plan.`, + )}
) @@ -328,14 +338,14 @@ const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGro />
) : ( - + - Create free account + {c('B1.Account.Session.Action').t`Create free account`} - Sign in + {c('B1.Account.Session.Action').t`Sign in`} ) @@ -343,7 +353,10 @@ const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGro return (
- + {hasSelection && ( - Clip text selection + {c('B7.FilesSubscriptionHelp.Help.Action').t`Clip text selection`} )} - {isScreenshotMode ? 'Capture visible' : 'Clip full page'} + {isScreenshotMode + ? c('B7.FilesSubscriptionHelp.Help.Action').t`Capture visible` + : c('B7.FilesSubscriptionHelp.Help.Action').t`Clip full page`} - Clip article + {c('B7.FilesSubscriptionHelp.Help.Action').t`Clip article`} { @@ -392,7 +407,9 @@ const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGro }} > - Select elements to {isScreenshotMode ? 'capture' : 'clip'} + {isScreenshotMode + ? c('B7.FilesSubscriptionHelp.Help.Action').t`Select elements to capture` + : c('B7.FilesSubscriptionHelp.Help.Action').t`Select elements to clip`} - Clip as screenshot + {c('B7.FilesSubscriptionHelp.Help.Action').t`Clip as screenshot`}
{defaultTag && ( @@ -413,7 +430,7 @@ const ClipperView = ({ applicationGroup }: { applicationGroup: WebApplicationGro unlinkItem={unselectTag} isBidirectional={false} /> - +
diff --git a/packages/web/src/javascripts/Components/CommandPalette/CommandPalette.tsx b/packages/web/src/javascripts/Components/CommandPalette/CommandPalette.tsx index e60bc3632c1..88b6b7d7ba3 100644 --- a/packages/web/src/javascripts/Components/CommandPalette/CommandPalette.tsx +++ b/packages/web/src/javascripts/Components/CommandPalette/CommandPalette.tsx @@ -1,4 +1,5 @@ import { observer } from 'mobx-react-lite' +import { c } from 'ttag' import { startTransition, useCallback, useEffect, useState } from 'react' import { useKeyboardService } from '../KeyboardServiceProvider' import { PlatformedKeyboardShortcut, TOGGLE_COMMAND_PALETTE } from '@standardnotes/ui-services' @@ -61,6 +62,17 @@ function ListItemDescription({ item }: { item: CommandPaletteItem }) { const Tabs = ['all', 'commands', 'notes', 'files', 'tags'] as const type TabId = (typeof Tabs)[number] +const getTabLabel = (id: TabId) => { + const labels: Record = { + all: c('B2.NavSharedUI.Label').t`all`, + commands: c('B2.NavSharedUI.Label').t`commands`, + notes: c('B2.NavSharedUI.Label').t`notes`, + files: c('B2.NavSharedUI.Label').t`files`, + tags: c('B2.NavSharedUI.Label').t`tags`, + } + return labels[id] +} + function CommandPaletteListItem({ id, item, @@ -105,7 +117,7 @@ function ComboboxInput() { { if (event.key !== 'Tab') { return @@ -157,7 +169,7 @@ function CommandPalette() { return keyboardService.addCommandHandler({ command: TOGGLE_COMMAND_PALETTE, category: 'General', - description: 'Toggle command palette', + description: c('B2.NavSharedUI.Action').t`Toggle command palette`, onKeyDown: (e) => { e.preventDefault() setIsOpen((open) => !open) @@ -218,7 +230,7 @@ function CommandPalette() { section, id: UuidGenerator.GenerateUuid(), itemUuid: item.uuid, - description: item.title || '', + description: item.title || c('B2.NavSharedUI.Placeholder').t``, icon: , } }, @@ -371,18 +383,22 @@ function CommandPalette() { disabled={hasNoItemsAtAll || (id !== 'all' && itemCountsPerTab[id] === 0)} accessibleWhenDisabled={false} > - {id} + {getTabLabel(id)} ))} {query.length > 0 && (hasNoItemsAtAll || hasNoItemsInSelectedTab) && ( -
No items found
+
+ {c('B2.NavSharedUI.Info').t`No items found`} +
)} {recents.length > 0 && ( - Recent + + {c('B2.NavSharedUI.Label').t`Recent`} + {recents.map((item, index) => ( {recents.length > 0 && ( - All commands + + {c('B2.NavSharedUI.Label').t`All commands`} + )} {items.map((item, index) => ( = ({ sandbox={sandboxAttributes.join(' ')} {...(usedInModal && { 'data-used-in-modal': true })} > - Loading + {c('B2.NavSharedUI.Info').t`Loading`} )} {isLoading &&
} diff --git a/packages/web/src/javascripts/Components/ComponentView/IsDeprecated.tsx b/packages/web/src/javascripts/Components/ComponentView/IsDeprecated.tsx index 19c506279c1..a63780646b3 100644 --- a/packages/web/src/javascripts/Components/ComponentView/IsDeprecated.tsx +++ b/packages/web/src/javascripts/Components/ComponentView/IsDeprecated.tsx @@ -1,4 +1,5 @@ import { FunctionComponent } from 'react' +import { c } from 'ttag' import Button from '@/Components/Button/Button' type Props = { @@ -13,13 +14,13 @@ const IsDeprecated: FunctionComponent = ({ deprecationMessage, dismissDep
- {deprecationMessage || 'This extension is deprecated.'} + {deprecationMessage || c('B2.NavSharedUI.Warning').t`This extension is deprecated.`}
diff --git a/packages/web/src/javascripts/Components/ComponentView/IssueOnLoading.tsx b/packages/web/src/javascripts/Components/ComponentView/IssueOnLoading.tsx index 08639726d54..f5e03ca16ff 100644 --- a/packages/web/src/javascripts/Components/ComponentView/IssueOnLoading.tsx +++ b/packages/web/src/javascripts/Components/ComponentView/IssueOnLoading.tsx @@ -1,6 +1,9 @@ import { FunctionComponent } from 'react' +import { c } from 'ttag' import Button from '@/Components/Button/Button' +const jtString = (value: unknown): string => (Array.isArray(value) ? value.join('') : String(value)) + type Props = { componentName: string reloadIframe: () => void @@ -12,12 +15,14 @@ const IssueOnLoading: FunctionComponent = ({ componentName, reloadIframe
-
There was an issue loading {componentName}.
+
+ {jtString(c('B2.NavSharedUI.Error').jt`There was an issue loading ${componentName}.`)} +
diff --git a/packages/web/src/javascripts/Components/ComponentView/NotEntitledBanner.tsx b/packages/web/src/javascripts/Components/ComponentView/NotEntitledBanner.tsx index f4ad979500a..2a1bc1502d7 100644 --- a/packages/web/src/javascripts/Components/ComponentView/NotEntitledBanner.tsx +++ b/packages/web/src/javascripts/Components/ComponentView/NotEntitledBanner.tsx @@ -1,5 +1,8 @@ import { AnyFeatureDescription, FeatureStatus, dateToLocalizedString } from '@standardnotes/snjs' import { FunctionComponent, useCallback } from 'react' +import { c } from 'ttag' + +const jtString = (value: unknown): string => (Array.isArray(value) ? value.join('') : String(value)) import Button from '@/Components/Button/Button' import { WarningCircle } from '../UIElements/WarningCircle' import { useApplication } from '../ApplicationProvider' @@ -13,16 +16,28 @@ const statusString = (featureStatus: FeatureStatus, expiredDate: Date | undefine switch (featureStatus) { case FeatureStatus.InCurrentPlanButExpired: if (expiredDate) { - return `Your subscription expired on ${dateToLocalizedString(expiredDate)}` + const expiredDateString = dateToLocalizedString(expiredDate) + return jtString( + c('B7.FilesSubscriptionHelp.Subscription.Info').jt`Your subscription expired on ${expiredDateString}`, + ) } else { - return 'Your subscription expired.' + return c('B7.FilesSubscriptionHelp.Subscription.Info').t`Your subscription expired.` } case FeatureStatus.NoUserSubscription: - return 'You do not have an active subscription' - case FeatureStatus.NotInCurrentPlan: - return `Please upgrade your plan to access ${featureName}` - default: - return `${featureName} is valid and you should not be seeing this message` + return c('B7.FilesSubscriptionHelp.Subscription.Info').t`You do not have an active subscription` + case FeatureStatus.NotInCurrentPlan: { + const featureNameLabel = featureName + return jtString( + c('B7.FilesSubscriptionHelp.Subscription.Info').jt`Please upgrade your plan to access ${featureNameLabel}`, + ) + } + default: { + const featureNameLabel = featureName + return jtString( + c('B7.FilesSubscriptionHelp.Subscription.Info') + .jt`${featureNameLabel} is valid and you should not be seeing this message`, + ) + } } } @@ -45,14 +60,16 @@ const NotEntitledBanner: FunctionComponent = ({ featureStatus, feature })
{statusString(featureStatus, expiredDate, feature.name)} -
{feature.name} is in a read-only state.
+
+ {jtString(c('B7.FilesSubscriptionHelp.Subscription.Info').jt`${feature.name} is in a read-only state.`)} +
{application.canShowPurchaseFlow() && ( )}
diff --git a/packages/web/src/javascripts/Components/ComponentView/OfflineRestricted.tsx b/packages/web/src/javascripts/Components/ComponentView/OfflineRestricted.tsx index 018fcad413f..d56d9ecb396 100644 --- a/packages/web/src/javascripts/Components/ComponentView/OfflineRestricted.tsx +++ b/packages/web/src/javascripts/Components/ComponentView/OfflineRestricted.tsx @@ -1,4 +1,5 @@ import { FunctionComponent } from 'react' +import { c } from 'ttag' const OfflineRestricted: FunctionComponent = () => { return ( @@ -7,19 +8,23 @@ const OfflineRestricted: FunctionComponent = () => {
-
You have restricted this component to not use a hosted version.
-
Locally-installed components are not available in the web application.
+
+ {c('B2.NavSharedUI.Info').t`You have restricted this component to not use a hosted version.`} +
+
+ {c('B2.NavSharedUI.Info').t`Locally-installed components are not available in the web application.`} +
-
To continue, choose from the following options:
+
{c('B2.NavSharedUI.Info') + .t`To continue, choose from the following options:`}
  • - Enable the Hosted option for this component by opening the Preferences {'>'} General {'>'} Advanced - Settings menu and toggling 'Use hosted when local is unavailable' under this component's options. - Then press Reload. + {c('B2.NavSharedUI.Info') + .t`Enable the Hosted option for this component by opening the Preferences > General > Advanced Settings menu and toggling 'Use hosted when local is unavailable' under this component's options. Then press Reload.`}
  • -
  • Use the desktop application.
  • +
  • {c('B2.NavSharedUI.Info').t`Use the desktop application.`}
diff --git a/packages/web/src/javascripts/Components/ComponentView/UrlMissing.tsx b/packages/web/src/javascripts/Components/ComponentView/UrlMissing.tsx index cd74f3bcc8a..862c01628d7 100644 --- a/packages/web/src/javascripts/Components/ComponentView/UrlMissing.tsx +++ b/packages/web/src/javascripts/Components/ComponentView/UrlMissing.tsx @@ -1,4 +1,7 @@ import { FunctionComponent } from 'react' +import { c } from 'ttag' + +const jtString = (value: unknown): string => (Array.isArray(value) ? value.join('') : String(value)) type Props = { componentName: string @@ -10,10 +13,17 @@ const UrlMissing: FunctionComponent = ({ componentName }) => {
-
This extension is missing its URL property.
-

In order to access your note immediately, please switch from {componentName} to the Plain Editor.

+
+ {c('B2.NavSharedUI.Error').t`This extension is missing its URL property.`} +
+

+ {jtString( + c('B2.NavSharedUI.Info') + .jt`In order to access your note immediately, please switch from ${componentName} to the Plain Editor.`, + )} +


-

Please contact help@standardnotes.com to remedy this issue.

+

{c('B2.NavSharedUI.Info').t`Please contact help@standardnotes.com to remedy this issue.`}

diff --git a/packages/web/src/javascripts/Components/ConfirmSignoutModal/ConfirmSignoutModal.tsx b/packages/web/src/javascripts/Components/ConfirmSignoutModal/ConfirmSignoutModal.tsx index 14d1a1ba68c..52a9a2a3103 100644 --- a/packages/web/src/javascripts/Components/ConfirmSignoutModal/ConfirmSignoutModal.tsx +++ b/packages/web/src/javascripts/Components/ConfirmSignoutModal/ConfirmSignoutModal.tsx @@ -87,7 +87,9 @@ const ConfirmSignoutModal: FunctionComponent = ({ application, applicatio {c('B1.Account.Session.Action').t`Cancel`}
diff --git a/packages/web/src/javascripts/Components/ContentListView/Calendar/Calendar.tsx b/packages/web/src/javascripts/Components/ContentListView/Calendar/Calendar.tsx index 70c7aa7ff3c..9b1042f38a8 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Calendar/Calendar.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/Calendar/Calendar.tsx @@ -1,7 +1,7 @@ import { useState, useEffect, FunctionComponent, useMemo } from 'react' import { CalendarActivity } from './CalendarActivity' import CalendarDay from './CalendarDay' -import { CalendarDays, CalendarDaysLeap, CalendarDaysOfTheWeek } from './Constants' +import { CalendarDays, CalendarDaysLeap, getCalendarDaysOfTheWeek } from './Constants' import { createActivityRecord, dateToDateOnlyString, isLeapYear, getStartDayOfMonth } from './CalendarUtilts' import { areDatesInSameDay } from '@/Utils/DateUtils' @@ -36,7 +36,7 @@ const Calendar: FunctionComponent = ({ activities, startDate, onDateSelec
- {CalendarDaysOfTheWeek.map((d) => ( + {getCalendarDaysOfTheWeek().map((d: string) => (
{d}
diff --git a/packages/web/src/javascripts/Components/ContentListView/Calendar/Constants.ts b/packages/web/src/javascripts/Components/ContentListView/Calendar/Constants.ts index 2541d87abfe..6441fea8466 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Calendar/Constants.ts +++ b/packages/web/src/javascripts/Components/ContentListView/Calendar/Constants.ts @@ -1,17 +1,29 @@ +import { c } from 'ttag' + export const CalendarDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] export const CalendarDaysLeap = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] -export const CalendarDaysOfTheWeek = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'] -export const CalendarMonths = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December', + +export const getCalendarDaysOfTheWeek = () => [ + c('B3.Notes.NoteList.Label').t`Mo`, + c('B3.Notes.NoteList.Label').t`Tu`, + c('B3.Notes.NoteList.Label').t`We`, + c('B3.Notes.NoteList.Label').t`Th`, + c('B3.Notes.NoteList.Label').t`Fr`, + c('B3.Notes.NoteList.Label').t`Sa`, + c('B3.Notes.NoteList.Label').t`Su`, +] + +export const getCalendarMonths = () => [ + c('B3.Notes.NoteList.Label').t`January`, + c('B3.Notes.NoteList.Label').t`February`, + c('B3.Notes.NoteList.Label').t`March`, + c('B3.Notes.NoteList.Label').t`April`, + c('B3.Notes.NoteList.Label').t`May`, + c('B3.Notes.NoteList.Label').t`June`, + c('B3.Notes.NoteList.Label').t`July`, + c('B3.Notes.NoteList.Label').t`August`, + c('B3.Notes.NoteList.Label').t`September`, + c('B3.Notes.NoteList.Label').t`October`, + c('B3.Notes.NoteList.Label').t`November`, + c('B3.Notes.NoteList.Label').t`December`, ] diff --git a/packages/web/src/javascripts/Components/ContentListView/Calendar/InfiniteCalendar.tsx b/packages/web/src/javascripts/Components/ContentListView/Calendar/InfiniteCalendar.tsx index 276c3a32d98..2242f1308e7 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Calendar/InfiniteCalendar.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/Calendar/InfiniteCalendar.tsx @@ -3,7 +3,7 @@ import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useSta import Calendar from './Calendar' import { CalendarActivity, CalendarActivityType } from './CalendarActivity' import { CalendarMonth } from './CalendarMonth' -import { CalendarMonths } from './Constants' +import { getCalendarMonths } from './Constants' import { insertMonths, insertMonthsWithTarget } from './CalendarUtilts' import { InfiniteScrollerInterface, InfinteScroller } from '../InfiniteScroller/InfiniteScroller' import { classNames } from '@standardnotes/utils' @@ -188,7 +188,7 @@ const InfiniteCalendar = forwardRef( 'text-center font-bold hover:bg-contrast', )} > - {CalendarMonths[activeDate.getMonth()]} {activeDate.getFullYear()} + {getCalendarMonths()[activeDate.getMonth()]} {activeDate.getFullYear()}
{expanded && ( ( selectPreviousItem, } = itemListController + const selectedItemsCount = itemListController.selectedItemsCount + const selectedItemsLabel = c('B3.Notes.NoteList.Info').jt`${selectedItemsCount} selected` + const innerRef = useRef(null) const { addDragTarget, removeDragTarget } = useFileDragNDrop() @@ -126,8 +130,10 @@ const ContentListView = forwardRef( const shouldAddDropTarget = !navigationController.isInAnySystemView() && !navigationController.isInSmartView() if (target && shouldAddDropTarget && currentTag) { + const tagTitle = currentTag.title addDragTarget(target, { - tooltipText: `Drop your files to upload and link them to tag "${currentTag.title}"`, + tooltipText: c('B3.Notes.NoteList.Info') + .jt`Drop your files to upload and link them to tag "${tagTitle}"` as unknown as string, callback: fileDropCallback, }) } @@ -178,7 +184,7 @@ const ContentListView = forwardRef( { command: NEXT_LIST_ITEM_KEYBOARD_COMMAND, category: 'Notes list', - description: 'Go to next item', + description: c('B3.Notes.NoteList.Action').t`Go to next item`, elements: [document.body, ...(searchBarElement ? [searchBarElement] : [])], onKeyDown: () => { if (searchBarElement === document.activeElement) { @@ -193,7 +199,7 @@ const ContentListView = forwardRef( { command: PREVIOUS_LIST_ITEM_KEYBOARD_COMMAND, category: 'Notes list', - description: 'Go to previous item', + description: c('B3.Notes.NoteList.Action').t`Go to previous item`, element: document.body, onKeyDown: () => { if (shouldUseTableView) { @@ -205,7 +211,7 @@ const ContentListView = forwardRef( { command: SEARCH_KEYBOARD_COMMAND, category: 'General', - description: 'Toggle global search', + description: c('B3.Notes.NoteList.Action').t`Toggle global search`, onKeyDown: (event) => { if (searchBarElement) { event.preventDefault() @@ -224,7 +230,7 @@ const ContentListView = forwardRef( { command: SELECT_ALL_ITEMS_KEYBOARD_COMMAND, category: 'General', - description: 'Select all items', + description: c('B3.Notes.NoteList.Action').t`Select all items`, onKeyDown: (event) => { const isTargetInsideContentList = (event.target as HTMLElement).closest(`#${ElementIds.ContentList}`) @@ -257,7 +263,9 @@ const ContentListView = forwardRef( if (shortcut) { shortcut = '(' + shortcut + ')' } - return isFilesSmartView ? `Upload file ${shortcut}` : `Create a new note in the selected tag ${shortcut}` + return isFilesSmartView + ? (c('B3.Notes.NoteList.Action').jt`Upload file ${shortcut}` as unknown as string) + : (c('B3.Notes.NoteList.Action').jt`Create a new note in the selected tag ${shortcut}` as unknown as string) }, [isFilesSmartView, shortcutForCreate]) useEffect( @@ -265,7 +273,9 @@ const ContentListView = forwardRef( application.commands.addWithShortcut( CREATE_NEW_NOTE_KEYBOARD_COMMAND, 'General', - isFilesSmartView ? 'Upload file' : 'Create new note', + isFilesSmartView + ? c('B3.Notes.NoteList.Action').t`Upload file` + : c('B3.Notes.NoteList.Action').t`Create new note`, (event) => { event?.preventDefault() void addNewItem() @@ -303,7 +313,7 @@ const ContentListView = forwardRef(
{isMobileScreen && !itemListController.isMultipleSelectionMode && ( @@ -343,7 +353,7 @@ const ContentListView = forwardRef( {itemListController.isMultipleSelectionMode && (
- +
-
{itemListController.selectedItemsCount} selected
- +
{selectedItemsLabel}
+
) diff --git a/packages/web/src/javascripts/Components/ContentListView/Header/AddItemMenuButton.tsx b/packages/web/src/javascripts/Components/ContentListView/Header/AddItemMenuButton.tsx index 73fbb8c9bed..506e59762ff 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Header/AddItemMenuButton.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/Header/AddItemMenuButton.tsx @@ -10,6 +10,7 @@ import { PhotoRecorder } from '@/Controllers/Moments/PhotoRecorder' import { classNames } from '@standardnotes/snjs' import { useEffect, useRef, useState } from 'react' import StyledTooltip from '@/Components/StyledTooltip/StyledTooltip' +import { c } from 'ttag' type Props = { isDailyEntry: boolean @@ -69,7 +70,7 @@ const AddItemMenuButton = ({ {canShowMenu && ( { @@ -79,7 +80,7 @@ const AddItemMenuButton = ({ align="center" className="py-2" > - + { addNewItem() @@ -96,7 +97,7 @@ const AddItemMenuButton = ({ }} > - Take photo + {c('B3.Notes.NoteList.Action').t`Take photo`} { @@ -105,7 +106,7 @@ const AddItemMenuButton = ({ }} > - Record video + {c('B3.Notes.NoteList.Label').t`Record video`} diff --git a/packages/web/src/javascripts/Components/ContentListView/Header/ContentListHeader.tsx b/packages/web/src/javascripts/Components/ContentListView/Header/ContentListHeader.tsx index 586d57bcbe5..17b469e3825 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Header/ContentListHeader.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/Header/ContentListHeader.tsx @@ -1,4 +1,5 @@ import { WebApplication } from '@/Application/WebApplication' +import { c } from 'ttag' import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import Icon from '../../Icon/Icon' import { classNames } from '@standardnotes/utils' @@ -80,7 +81,9 @@ const ContentListHeader = ({ if (event === ApplicationEvent.SyncStatusChanged) { setSyncSubtitle( - syncStatus.syncInProgress && !application.sync.completedOnlineDownloadFirstSync ? 'Syncing...' : '', + syncStatus.syncInProgress && !application.sync.completedOnlineDownloadFirstSync + ? c('B3.Notes.NoteList.Status').t`Syncing...` + : '', ) return } @@ -91,7 +94,9 @@ const ContentListHeader = ({ return } - setSyncSubtitle(`Loading ${localDataCurrent}/${localDataTotal} items...`) + setSyncSubtitle( + c('B3.Notes.NoteList.Info').jt`Loading ${localDataCurrent}/${localDataTotal} items...` as unknown as string, + ) return } }) @@ -107,7 +112,7 @@ const ContentListHeader = ({ () => application.commands.add( 'open-display-opts-menu', - 'Open display options menu', + c('B3.Notes.NoteList.Action').t`Open display options menu`, toggleDisplayOptionsMenu, 'sort-descending', ), @@ -123,7 +128,7 @@ const ContentListHeader = ({ onClick={toggleDisplayOptionsMenu} ref={displayOptionsButtonRef} icon="sort-descending" - label="Display options menu" + label={c('B3.Notes.NoteList.AriaLabel').t`Display options menu`} /> {panelTitle}
{showSyncSubtitle && (
- {outOfSync ? 'Potentially Out of Sync' : syncSubtitle} + {outOfSync ? c('B3.Notes.NoteList.Status').t`Potentially Out of Sync` : syncSubtitle}
)} {optionsSubtitle &&
{optionsSubtitle}
} diff --git a/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenu.tsx b/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenu.tsx index 06e55b7db1a..47b324c9162 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenu.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenu.tsx @@ -27,6 +27,7 @@ import { Pill } from '@/Components/Preferences/PreferencesComponents/Content' import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery' import { PaneLayout } from '@/Controllers/PaneController/PaneLayout' import MenuSection from '@/Components/Menu/MenuSection' +import { c } from 'ttag' const DailyEntryModeEnabled = true @@ -286,11 +287,18 @@ const DisplayOptionsMenu: FunctionComponent = ({ const shouldHideNonApplicableOptions = isTableViewEnabled && !isMobileScreen return ( - -
Preferences for
+ +
+ {c('B3.Notes.NoteList.Label').t`Preferences for`} +
- + = ({
{currentMode === 'tag' && ( )}
@@ -310,16 +318,18 @@ const DisplayOptionsMenu: FunctionComponent = ({ )} - + = ({ checked={preferences.sortBy === CollectionSort.UpdatedAt} >
- Date modified + {c('B3.Notes.NoteList.Label').t`Date modified`}
@@ -338,7 +348,7 @@ const DisplayOptionsMenu: FunctionComponent = ({ checked={preferences.sortBy === CollectionSort.CreatedAt} >
- Creation date + {c('B3.Notes.NoteList.Label').t`Creation date`}
@@ -349,13 +359,13 @@ const DisplayOptionsMenu: FunctionComponent = ({ checked={preferences.sortBy === CollectionSort.Title} >
- Title + {c('B3.Notes.NoteList.Label').t`Title`}
- + {!shouldHideNonApplicableOptions && !isFilesSmartView && ( = ({ checked={!preferences.hideNotePreview} onChange={toggleHidePreview} > -
Show note preview
+
{c('B3.Notes.NoteList.Label').t`Show note preview`}
)} = ({ checked={!preferences.hideDate} onChange={toggleHideDate} > - Show date + {c('B3.Notes.NoteList.Action').t`Show date`} = ({ checked={!preferences.hideTags} onChange={toggleHideTags} > - Show tags + {c('B3.Notes.NoteList.Action').t`Show tags`} = ({ checked={!preferences.hideEditorIcon} onChange={toggleEditorIcon} > - Show icon + {c('B3.Notes.NoteList.Action').t`Show icon`}
{!shouldHideNonApplicableOptions && ( - + - Show pinned + {c('B3.Notes.NoteList.Action').t`Show pinned`} = ({ checked={!preferences.hideProtected} onChange={toggleHideProtected} > - Show protected + {c('B3.Notes.NoteList.Action').t`Show protected`} = ({ checked={Boolean(preferences.showArchived)} onChange={toggleShowArchived} > - Show archived + {c('B3.Notes.NoteList.Action').t`Show archived`} = ({ checked={Boolean(preferences.showTrashed)} onChange={toggleShowTrashed} > - Show trashed + {c('B3.Notes.NoteList.Action').t`Show trashed`} )} @@ -439,12 +449,16 @@ const DisplayOptionsMenu: FunctionComponent = ({ >
-
Daily Notebook
+
+ {c('B3.Notes.NoteList.Label').t`Daily Notebook`} +
- Labs + {c('B3.Notes.NoteList.Label').t`Labs`}
-
Capture new notes daily with a calendar-based layout
+
+ {c('B3.Notes.NoteList.Label').t`Capture new notes daily with a calendar-based layout`} +
@@ -460,19 +474,23 @@ const DisplayOptionsMenu: FunctionComponent = ({ >
-
Table view
+
+ {c('B3.Notes.NoteList.Label').t`Table view`} +
- Labs + {c('B3.Notes.NoteList.Label').t`Labs`}
-
Display the notes and files in the current tag in a table layout
+
+ {c('B3.Notes.NoteList.Label').t`Display the notes and files in the current tag in a table layout`} +
)} {!shouldHideNonApplicableOptions && (!isSystemTag || currentMode === 'global') && ( - + = ({ return (
-
Note Type
+
{c('B3.Notes.NoteList.Label').t`Note Type`}
selectEditorForNewNoteDefault(value as EditorOption['value'])} @@ -188,12 +189,13 @@ const NewNotePreferences: FunctionComponent = ({
-
Title Format
+
{c('B3.Notes.NoteList.Label') + .t`Title Format`}
= ({ 'w-full min-w-55 rounded border border-solid border-passive-3 bg-default px-2 py-1.5 text-sm md:translucent-ui:bg-transparent', 'focus-within:ring-2 focus-within:ring-info', )} - placeholder="e.g. YYYY-MM-DD" + placeholder={c('B3.Notes.NoteList.Label').t`e.g. YYYY-MM-DD`} value={customNoteTitleFormat} onChange={handleCustomFormatInputChange} spellCheck={false} />
- Preview: + {c('B3.Notes.NoteList.Label').t`Preview:`} @@ -234,9 +236,10 @@ const NewNotePreferences: FunctionComponent = ({ } }} > - Options + {c('B3.Notes.NoteList.Action').t`Options`} - . Use [] to escape formatting. + . {c('B3.Notes.NoteList.Info').t`Use`} []{' '} + {c('B3.Notes.NoteList.Info').t`to escape formatting.`}
)} diff --git a/packages/web/src/javascripts/Components/ContentListView/Header/NoteTitleFormatOptions.tsx b/packages/web/src/javascripts/Components/ContentListView/Header/NoteTitleFormatOptions.tsx index 2daf756e103..dbd57bf83a5 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Header/NoteTitleFormatOptions.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/Header/NoteTitleFormatOptions.tsx @@ -1,20 +1,21 @@ import { NewNoteTitleFormat } from '@standardnotes/snjs' +import { c } from 'ttag' export const NoteTitleFormatOptions = [ { - label: 'Current date and time', + label: c('B3.Notes.NoteList.Label').t`Current date and time`, value: NewNoteTitleFormat.CurrentDateAndTime, }, { - label: 'Current note count', + label: c('B3.Notes.NoteList.Label').t`Current note count`, value: NewNoteTitleFormat.CurrentNoteCount, }, { - label: 'Custom format', + label: c('B3.Notes.NoteList.Label').t`Custom format`, value: NewNoteTitleFormat.CustomFormat, }, { - label: 'Empty', + label: c('B3.Notes.NoteList.Label').t`Empty`, value: NewNoteTitleFormat.Empty, }, ] diff --git a/packages/web/src/javascripts/Components/ContentListView/Header/SearchButton.tsx b/packages/web/src/javascripts/Components/ContentListView/Header/SearchButton.tsx index b20f7c67e23..8e00468a76b 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Header/SearchButton.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/Header/SearchButton.tsx @@ -1,4 +1,5 @@ import RoundIconButton from '@/Components/Button/RoundIconButton' +import { c } from 'ttag' import ClearInputButton from '@/Components/ClearInputButton/ClearInputButton' import Icon from '@/Components/Icon/Icon' import DecoratedInput from '@/Components/Input/DecoratedInput' @@ -31,7 +32,7 @@ const SearchButton = ({ itemListController }: Props) => { ), input: 'text-base placeholder:text-passive-0 lg:text-sm', }} - placeholder={'Search...'} + placeholder={c('B3.Notes.NoteList.Placeholder').t`Search...`} value={noteFilterText} ref={(node) => { if (node && document.activeElement !== node) { @@ -50,7 +51,7 @@ const SearchButton = ({ itemListController }: Props) => { setIsSearchBarVisible(!isSearchBarVisible) }} icon={isSearchBarVisible ? 'close' : 'search'} - label="Search" + label={c('B3.Notes.NoteList.AriaLabel').t`Search`} /> ) diff --git a/packages/web/src/javascripts/Components/ContentListView/ListItemConflictIndicator.tsx b/packages/web/src/javascripts/Components/ContentListView/ListItemConflictIndicator.tsx index 15ac09dd3a8..d937ce0e01b 100644 --- a/packages/web/src/javascripts/Components/ContentListView/ListItemConflictIndicator.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/ListItemConflictIndicator.tsx @@ -1,4 +1,5 @@ import { FunctionComponent } from 'react' +import { c } from 'ttag' import { ListableContentItem } from './Types/ListableContentItem' type Props = { @@ -11,7 +12,7 @@ const ListItemConflictIndicator: FunctionComponent = ({ item }) => { return item.conflictOf ? (
-
Conflicted Copy
+
{c('B3.Notes.NoteActions.Label').t`Conflicted Copy`}
) : null diff --git a/packages/web/src/javascripts/Components/ContentListView/ListItemFlagIcons.tsx b/packages/web/src/javascripts/Components/ContentListView/ListItemFlagIcons.tsx index cfa8493f8e8..e38ca219ad2 100644 --- a/packages/web/src/javascripts/Components/ContentListView/ListItemFlagIcons.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/ListItemFlagIcons.tsx @@ -1,4 +1,5 @@ import { FunctionComponent } from 'react' +import { c } from 'ttag' import Icon from '@/Components/Icon/Icon' import { ListableContentItem } from './Types/ListableContentItem' import { classNames } from '@standardnotes/snjs' @@ -27,33 +28,63 @@ const ListItemFlagIcons: FunctionComponent = ({ return (
{item.locked && ( - - + + )} {item.trashed && ( - - + + )} {item.archived && ( - - + + )} {hasFiles && ( - - + + )} {item.starred && ( - - + + )} {isFileBackedUp && ( - - + + )}
diff --git a/packages/web/src/javascripts/Components/ContentListView/ListItemMetadata.tsx b/packages/web/src/javascripts/Components/ContentListView/ListItemMetadata.tsx index 88b20fbd53e..5e349116a71 100644 --- a/packages/web/src/javascripts/Components/ContentListView/ListItemMetadata.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/ListItemMetadata.tsx @@ -1,5 +1,6 @@ import { CollectionSort, SortableItem } from '@standardnotes/snjs' import { FunctionComponent } from 'react' +import { c } from 'ttag' import { ListableContentItem } from './Types/ListableContentItem' type Props = { @@ -21,9 +22,18 @@ const ListItemMetadata: FunctionComponent = ({ item, hideDate, sortBy }) return (
- {item.protected && Protected {hideDate ? '' : ' • '}} - {!hideDate && showModifiedDate && Modified {item.updatedAtString || 'Now'}} - {!hideDate && !showModifiedDate && {item.createdAtString || 'Now'}} + {item.protected && ( + + {c('B3.Notes.NoteList.Label').t`Protected`} + {hideDate ? '' : ' • '} + + )} + {!hideDate && showModifiedDate && ( + + {c('B3.Notes.NoteList.Label').t`Modified`} {item.updatedAtString || c('B3.Notes.NoteList.Label').t`Now`} + + )} + {!hideDate && !showModifiedDate && {item.createdAtString || c('B3.Notes.NoteList.Label').t`Now`}}
) } diff --git a/packages/web/src/javascripts/Components/ContentTableView/ContentTableView.tsx b/packages/web/src/javascripts/Components/ContentTableView/ContentTableView.tsx index 99a727d477a..4026ce2c0c3 100644 --- a/packages/web/src/javascripts/Components/ContentTableView/ContentTableView.tsx +++ b/packages/web/src/javascripts/Components/ContentTableView/ContentTableView.tsx @@ -16,6 +16,7 @@ import { isNote, } from '@standardnotes/snjs' import { useState, useEffect, useCallback, useMemo, useRef } from 'react' +import { c } from 'ttag' import { FileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction' import { getFileIconComponent } from '../FilePreview/getFileIconComponent' import Popover from '../Popover/Popover' @@ -65,7 +66,7 @@ const ContextMenuCell = ({ items }: { items: DecryptedItemInterface[] }) => { { @@ -75,7 +76,7 @@ const ContextMenuCell = ({ items }: { items: DecryptedItemInterface[] }) => { align="start" className="py-2" > - + {allItemsAreFiles && ( { @@ -118,7 +119,7 @@ const ItemLinksCell = ({ item }: { item: DecryptedItemInterface }) => { { @@ -163,7 +164,7 @@ const ItemNameCell = ({ item, hideIcon }: { item: DecryptedItemInterface; hideIc {backupInfo && (
@@ -172,8 +173,13 @@ const ItemNameCell = ({ item, hideIcon }: { item: DecryptedItemInterface; hideIc {item.title} {item.protected && ( - - + + )}
@@ -196,6 +202,8 @@ const AttachedToCell = ({ item }: { item: DecryptedItemInterface }) => { return null } + const additionalLinksCount = allLinks.length - 1 + return (
{ }} isBidirectional={false} /> - {allLinks.length - 1 >= 1 && and {allLinks.length - 1} more...} + {additionalLinksCount >= 1 && {c('B3.Notes.NoteList.Info').jt`and ${additionalLinksCount} more...`}}
) } @@ -274,12 +282,12 @@ const ContentTableView = ({ application, items }: Props) => { const columnDefs: TableColumn[] = useMemo( () => [ { - name: 'Name', + name: c('B3.Notes.NoteList.Label').t`Name`, sortBy: 'title', cell: (item) => , }, { - name: 'Upload date', + name: c('B3.Notes.NoteList.Label').t`Upload date`, sortBy: 'created_at', cell: (item) => { return formatDateForContextMenu(item.created_at) @@ -287,7 +295,7 @@ const ContentTableView = ({ application, items }: Props) => { hidden: isSmallBreakpoint || hideDate, }, { - name: 'Size', + name: c('B3.Notes.NoteList.Label').t`Size`, sortBy: 'decryptedSize', cell: (item) => { return item instanceof FileItem ? formatSizeToReadableString(item.decryptedSize) : null @@ -295,7 +303,7 @@ const ContentTableView = ({ application, items }: Props) => { hidden: isSmallBreakpoint || !listHasFiles, }, { - name: 'Attached to', + name: c('B3.Notes.NoteList.Label').t`Attached to`, hidden: isSmallBreakpoint || isMediumBreakpoint || isLargeBreakpoint || hideTags, cell: (item) => , }, @@ -354,7 +362,7 @@ const ContentTableView = ({ application, items }: Props) => { {contextMenuPosition && contextMenuItem && ( { @@ -366,7 +374,7 @@ const ContentTableView = ({ application, items }: Props) => { className="py-2" > {contextMenuItem instanceof FileItem && ( - + { )} {contextMenuItem instanceof SNNote && ( - + )} diff --git a/packages/web/src/javascripts/Components/EditorWidthSelectionModal/EditorWidthSelectionModal.tsx b/packages/web/src/javascripts/Components/EditorWidthSelectionModal/EditorWidthSelectionModal.tsx index 7869eb1f1c9..2151055b001 100644 --- a/packages/web/src/javascripts/Components/EditorWidthSelectionModal/EditorWidthSelectionModal.tsx +++ b/packages/web/src/javascripts/Components/EditorWidthSelectionModal/EditorWidthSelectionModal.tsx @@ -1,4 +1,5 @@ import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery' +import { c } from 'ttag' import { classNames, EditorLineWidth, SNNote, PrefDefaults, LocalPrefKey } from '@standardnotes/snjs' import { useCallback, useEffect, useMemo, useState } from 'react' import Button from '../Button/Button' @@ -44,19 +45,19 @@ const EditorWidthSelectionModal = ({ const options = useMemo( () => [ { - label: 'Narrow', + label: c('B4.Notes.EditorOptions.Label').t`Narrow`, value: EditorLineWidth.Narrow, }, { - label: 'Wide', + label: c('B4.Notes.EditorOptions.Label').t`Wide`, value: EditorLineWidth.Wide, }, { - label: 'Dynamic', + label: c('B4.Notes.EditorOptions.Label').t`Dynamic`, value: EditorLineWidth.Dynamic, }, { - label: 'Full width', + label: c('B4.Notes.EditorOptions.Label').t`Full width`, value: EditorLineWidth.FullWidth, }, ], @@ -71,13 +72,13 @@ const EditorWidthSelectionModal = ({ const actions = useMemo( (): ModalAction[] => [ { - label: 'Cancel', + label: c('B4.Notes.EditorOptions.Action').t`Cancel`, type: 'cancel', onClick: close, mobileSlot: 'left', }, { - label: 'Done', + label: c('B4.Notes.EditorOptions.Action').t`Done`, type: 'primary', onClick: accept, mobileSlot: 'right', @@ -97,7 +98,7 @@ const EditorWidthSelectionModal = ({ return ( } customFooter={<>} @@ -119,7 +120,7 @@ const EditorWidthSelectionModal = ({
{value === EditorLineWidth.Narrow || value === EditorLineWidth.Wide - ? `Max. ${EditorMaxWidths[value]}` + ? c('B4.Notes.EditorOptions.Info').jt`Max. ${EditorMaxWidths[value]}` : EditorMaxWidths[value]}
@@ -132,16 +133,18 @@ const EditorWidthSelectionModal = ({
)} setValue(value as EditorLineWidth)} />
- +
@@ -181,7 +184,7 @@ const EditorWidthSelectionModalWrapper = () => { return application.commands.addWithShortcut( CHANGE_EDITOR_WIDTH_COMMAND, 'Current note', - 'Change editor width', + c('B4.Notes.EditorOptions.Action').t`Change editor width`, (_, data) => { if (typeof data === 'boolean' && data) { setIsGlobal(data) diff --git a/packages/web/src/javascripts/Components/FileContextMenu/FileContextMenu.tsx b/packages/web/src/javascripts/Components/FileContextMenu/FileContextMenu.tsx index 1bc5120c3b5..f7f73e3fe37 100644 --- a/packages/web/src/javascripts/Components/FileContextMenu/FileContextMenu.tsx +++ b/packages/web/src/javascripts/Components/FileContextMenu/FileContextMenu.tsx @@ -1,6 +1,7 @@ import { FilesController } from '@/Controllers/FilesController' import { observer } from 'mobx-react-lite' import { FunctionComponent } from 'react' +import { c } from 'ttag' import Menu from '../Menu/Menu' import Popover from '../Popover/Popover' import FileMenuOptions from './FileMenuOptions' @@ -17,14 +18,14 @@ const FileContextMenu: FunctionComponent = observer(({ filesController, i return ( setShowFileContextMenu(!showFileContextMenu)} align="start" className="md:pb-2" > - + setShowFileContextMenu(false)} diff --git a/packages/web/src/javascripts/Components/FileContextMenu/FileContextMenuBackupOption.tsx b/packages/web/src/javascripts/Components/FileContextMenu/FileContextMenuBackupOption.tsx index a054b4dbf23..c62b8a7aa2e 100644 --- a/packages/web/src/javascripts/Components/FileContextMenu/FileContextMenuBackupOption.tsx +++ b/packages/web/src/javascripts/Components/FileContextMenu/FileContextMenuBackupOption.tsx @@ -1,4 +1,5 @@ import { FunctionComponent, useCallback, useEffect, useState } from 'react' +import { c } from 'ttag' import MenuItem from '../Menu/MenuItem' import { useApplication } from '../ApplicationProvider' import { FileBackupRecord, FileItem } from '@standardnotes/snjs' @@ -48,7 +49,12 @@ export const FileContextMenuBackupOption: FunctionComponent<{ file: FileItem }> onClick={openFileBackup} >
-
Backed up on {dateToStringStyle1(backupInfo.backedUpOn)}
+
+ {(() => { + const backedUpOn = dateToStringStyle1(backupInfo.backedUpOn) + return c('B7.FilesSubscriptionHelp.Files.Info').jt`Backed up on ${backedUpOn}` as unknown as string + })()} +
{backupAbsolutePath}
@@ -62,8 +68,9 @@ export const FileContextMenuBackupOption: FunctionComponent<{ file: FileItem }> onClick={configureFileBackups} >
-
Configure file backups
-
File not backed up locally
+
{c('B7.FilesSubscriptionHelp.Files.Action').t`Configure file backups`}
+
{c('B7.FilesSubscriptionHelp.Files.Info') + .t`File not backed up locally`}
)} diff --git a/packages/web/src/javascripts/Components/FileContextMenu/FileMenuOptions.tsx b/packages/web/src/javascripts/Components/FileContextMenu/FileMenuOptions.tsx index fa51741a1ec..5b9231f8dcb 100644 --- a/packages/web/src/javascripts/Components/FileContextMenu/FileMenuOptions.tsx +++ b/packages/web/src/javascripts/Components/FileContextMenu/FileMenuOptions.tsx @@ -16,6 +16,7 @@ import { iconClass } from '../NotesOptions/ClassNames' import { useApplication } from '../ApplicationProvider' import MenuSection from '../Menu/MenuSection' import { ToastType, addToast } from '@standardnotes/toast' +import { c } from 'ttag' type Props = { closeMenu: () => void @@ -84,7 +85,7 @@ const FileMenuOptions: FunctionComponent = ({ }) if (selectedFiles.length === 0) { - return
No files selected
+ return
{c('B7.FilesSubscriptionHelp.Files.Info').t`No files selected`}
} return ( @@ -94,12 +95,12 @@ const FileMenuOptions: FunctionComponent = ({ {isFileAttachedToNote ? ( - Detach from note + {c('B7.FilesSubscriptionHelp.Files.Info').t`Detach from note`} ) : shouldShowAttachOption ? ( - Attach to note + {c('B7.FilesSubscriptionHelp.Files.Info').t`Attach to note`} ) : null} @@ -127,7 +128,7 @@ const FileMenuOptions: FunctionComponent = ({ disabled={areSomeFilesInReadonlySharedVault} > - Password protect + {c('B7.FilesSubscriptionHelp.Files.Info').t`Password protect`} @@ -138,7 +139,7 @@ const FileMenuOptions: FunctionComponent = ({ }} > - Download {canShowZipDownloadOption ? 'separately' : ''} + {c('B7.FilesSubscriptionHelp.Files.Action').t`Download`} {canShowZipDownloadOption ? 'separately' : ''} {canShowZipDownloadOption && ( = ({ console.error(error) addToast({ type: ToastType.Error, - message: error.message || 'Failed to download files as archive', + message: + error.message || c('B7.FilesSubscriptionHelp.Files.Error').t`Failed to download files as archive`, }) }) closeMenu() }} > - Download as archive + {c('B7.FilesSubscriptionHelp.Files.Action').t`Download as archive`} )} {shouldShowRenameOption && ( @@ -168,7 +170,7 @@ const FileMenuOptions: FunctionComponent = ({ disabled={areSomeFilesInReadonlySharedVault} > - Rename + {c('B7.FilesSubscriptionHelp.Files.Info').t`Rename`} )} = ({ disabled={areSomeFilesInReadonlySharedVault} > - Delete permanently + {c('B7.FilesSubscriptionHelp.Files.Action').t`Delete permanently`} @@ -188,11 +190,16 @@ const FileMenuOptions: FunctionComponent = ({
{!hasSelectedMultipleFiles && (
- File ID: {selectedFiles[0].uuid} + {c('B7.FilesSubscriptionHelp.Files.Info').t`File ID:`}{' '} + {selectedFiles[0].uuid}
)}
- {hasSelectedMultipleFiles ? 'Total Size:' : 'Size:'}{' '} + + {hasSelectedMultipleFiles + ? c('B7.FilesSubscriptionHelp.Files.Info').t`Total Size:` + : c('B7.FilesSubscriptionHelp.Files.Info').t`Size:`} + {' '} {formatSizeToReadableString(totalFileSize)}
diff --git a/packages/web/src/javascripts/Components/FileContextMenu/FileOptionsPanel.tsx b/packages/web/src/javascripts/Components/FileContextMenu/FileOptionsPanel.tsx index 9a1d392aae0..91bf85237c5 100644 --- a/packages/web/src/javascripts/Components/FileContextMenu/FileOptionsPanel.tsx +++ b/packages/web/src/javascripts/Components/FileContextMenu/FileOptionsPanel.tsx @@ -1,5 +1,6 @@ import { useCallback, useRef, useState } from 'react' import { observer } from 'mobx-react-lite' +import { c } from 'ttag' import FileMenuOptions from './FileMenuOptions' import Popover from '../Popover/Popover' import RoundIconButton from '../Button/RoundIconButton' @@ -18,15 +19,20 @@ const FilesOptionsPanel = ({ itemListController }: Props) => { return ( <> - + - + { diff --git a/packages/web/src/javascripts/Components/FileDragNDropProvider.tsx b/packages/web/src/javascripts/Components/FileDragNDropProvider.tsx index 5b90c8b3404..edb42e58536 100644 --- a/packages/web/src/javascripts/Components/FileDragNDropProvider.tsx +++ b/packages/web/src/javascripts/Components/FileDragNDropProvider.tsx @@ -7,6 +7,7 @@ import { FileItem, SNNote } from '@standardnotes/snjs' import { useMemo, useState, createContext, ReactNode, useRef, useCallback, useEffect, useContext, memo } from 'react' import Portal from './Portal/Portal' import { ElementIds } from '@/Constants/ElementIDs' +import { c } from 'ttag' type FileDragTargetCommonData = { tooltipText: string @@ -273,7 +274,9 @@ const FileDragNDropProvider = ({ application, children }: Props) => { {isDraggingFiles ? ( <>
- {tooltipText.length ? tooltipText : 'Drop your files to upload them'} + {tooltipText.length + ? tooltipText + : c('B7.FilesSubscriptionHelp.Files.Info').t`Drop your files to upload them`}
) : null} diff --git a/packages/web/src/javascripts/Components/FilePreview/FilePreview.tsx b/packages/web/src/javascripts/Components/FilePreview/FilePreview.tsx index 8f777b05833..cadec99ca73 100644 --- a/packages/web/src/javascripts/Components/FilePreview/FilePreview.tsx +++ b/packages/web/src/javascripts/Components/FilePreview/FilePreview.tsx @@ -7,6 +7,7 @@ import { fileProgressToHumanReadableString, } from '@standardnotes/snjs' import { useEffect, useMemo, useState } from 'react' +import { c } from 'ttag' import Spinner from '@/Components/Spinner/Spinner' import FilePreviewError from './FilePreviewError' import { isFileTypePreviewable } from './isFilePreviewable' @@ -101,20 +102,24 @@ const FilePreview = ({ return (
-
This file is protected.
+
{c('B7.FilesSubscriptionHelp.Files.Info') + .t`This file is protected.`}

{hasProtectionSources - ? 'Authenticate to view this file.' - : 'Add a passcode or create an account to require authentication to view this file.'} + ? c('B7.FilesSubscriptionHelp.Files.Info').t`Authenticate to view this file.` + : c('B7.FilesSubscriptionHelp.Files.Info') + .t`Add a passcode or create an account to require authentication to view this file.`}

{!hasProtectionSources && ( )}
@@ -134,7 +139,7 @@ const FilePreview = ({ {fileProgressToHumanReadableString(downloadProgress, file.name, { showPercent: false })} ) : ( - Loading... + {c('B7.FilesSubscriptionHelp.Files.Info').t`Loading...`} )}
) : downloadedBytes ? ( diff --git a/packages/web/src/javascripts/Components/FilePreview/FilePreviewError.tsx b/packages/web/src/javascripts/Components/FilePreview/FilePreviewError.tsx index 79c0db64505..cc42cfd88d9 100644 --- a/packages/web/src/javascripts/Components/FilePreview/FilePreviewError.tsx +++ b/packages/web/src/javascripts/Components/FilePreview/FilePreviewError.tsx @@ -1,6 +1,7 @@ import { FilesController } from '@/Controllers/FilesController' import { NoPreviewIllustration } from '@standardnotes/icons' import { FileItem } from '@standardnotes/snjs' +import { c } from 'ttag' import { FileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction' import Button from '../Button/Button' @@ -15,11 +16,13 @@ const FilePreviewError = ({ file, filesController, isFilePreviewable, tryAgainCa return (
-
This file can't be previewed.
+
{c('B7.FilesSubscriptionHelp.Files.Info') + .t`This file can't be previewed.`}
{isFilePreviewable ? ( <>
- There was an error loading the file. Try again, or download the file and open it using another application. + {c('B7.FilesSubscriptionHelp.Files.Error') + .t`There was an error loading the file. Try again, or download the file and open it using another application.`}
) : ( <>
- To view this file, download it and open it using another application. + {c('B7.FilesSubscriptionHelp.Files.Info') + .t`To view this file, download it and open it using another application.`}
)} diff --git a/packages/web/src/javascripts/Components/FilePreview/FilePreviewInfoPanel.tsx b/packages/web/src/javascripts/Components/FilePreview/FilePreviewInfoPanel.tsx index 4ef5ca155dc..c8198557032 100644 --- a/packages/web/src/javascripts/Components/FilePreview/FilePreviewInfoPanel.tsx +++ b/packages/web/src/javascripts/Components/FilePreview/FilePreviewInfoPanel.tsx @@ -1,6 +1,7 @@ import { formatSizeToReadableString } from '@standardnotes/filepicker' import { FileItem } from '@standardnotes/snjs' import { FunctionComponent } from 'react' +import { c } from 'ttag' import Icon from '@/Components/Icon/Icon' type Props = { @@ -12,25 +13,29 @@ const FilePreviewInfoPanel: FunctionComponent = ({ file }) => {
-
File information
+
{c('B7.FilesSubscriptionHelp.Files.Info').t`File information`}
- Type: {file.mimeType} + {c('B7.FilesSubscriptionHelp.Files.Info').t`Type:`} {file.mimeType}
- Decrypted Size: {formatSizeToReadableString(file.decryptedSize)} + {c('B7.FilesSubscriptionHelp.Files.Info').t`Decrypted Size:`}{' '} + {formatSizeToReadableString(file.decryptedSize)}
- Encrypted Size: {formatSizeToReadableString(file.encryptedSize)} + {c('B7.FilesSubscriptionHelp.Files.Info').t`Encrypted Size:`}{' '} + {formatSizeToReadableString(file.encryptedSize)}
- Created: {file.created_at.toLocaleString()} + {c('B7.FilesSubscriptionHelp.Files.Info').t`Created:`}{' '} + {file.created_at.toLocaleString()}
- Last Modified: {file.userModifiedDate.toLocaleString()} + {c('B7.FilesSubscriptionHelp.Files.Info').t`Last Modified:`}{' '} + {file.userModifiedDate.toLocaleString()}
- File ID: {file.uuid} + {c('B7.FilesSubscriptionHelp.Files.Info').t`File ID:`} {file.uuid}
) diff --git a/packages/web/src/javascripts/Components/FilePreview/FilePreviewModal.tsx b/packages/web/src/javascripts/Components/FilePreview/FilePreviewModal.tsx index 73ed056eb3e..ef96aef71d3 100644 --- a/packages/web/src/javascripts/Components/FilePreview/FilePreviewModal.tsx +++ b/packages/web/src/javascripts/Components/FilePreview/FilePreviewModal.tsx @@ -1,5 +1,6 @@ import { WebApplication } from '@/Application/WebApplication' import { FunctionComponent, KeyboardEventHandler, useCallback, useMemo, useRef, useState } from 'react' +import { c } from 'ttag' import { getFileIconComponent } from './getFileIconComponent' import Icon from '@/Components/Icon/Icon' import FilePreviewInfoPanel from './FilePreviewInfoPanel' @@ -122,26 +123,30 @@ const FilePreviewModal = observer(({ application }: Props) => { close={dismiss} actions={[ { - label: 'Done', + label: c('B7.FilesSubscriptionHelp.Files.Label').t`Done`, type: 'primary', onClick: dismiss, hidden: !isMobileScreen, mobileSlot: 'right', }, { - label: 'Show file options', + label: c('B7.FilesSubscriptionHelp.Files.Label').t`Show file options`, type: 'secondary', onClick: toggleOptionsMenu, hidden: !isMobileScreen, }, { - label: `${showFileInfoPanel ? 'Hide' : 'Show'} file info`, + label: showFileInfoPanel + ? c('B7.FilesSubscriptionHelp.Files.Action').t`Hide file info` + : c('B7.FilesSubscriptionHelp.Files.Action').t`Show file info`, type: 'secondary', onClick: toggleInfoPanel, hidden: !isMobileScreen, }, { - label: `${showLinkedBubblesContainer ? 'Hide' : 'Show'} links section`, + label: showLinkedBubblesContainer + ? c('B7.FilesSubscriptionHelp.Files.Action').t`Hide links section` + : c('B7.FilesSubscriptionHelp.Files.Action').t`Show links section`, type: 'secondary', onClick: toggleLinkedBubblesContainer, hidden: !isMobileScreen, @@ -171,7 +176,7 @@ const FilePreviewModal = observer(({ application }: Props) => { right={[
{!isReadonly && ( - + )} - + - + { className="md:pb-2" overrideZIndex="z-modal" > - + { /> - + @@ -245,7 +250,7 @@ const FilePreviewModal = observer(({ application }: Props) => {
) diff --git a/packages/web/src/javascripts/Components/FilePreview/VideoPreview.tsx b/packages/web/src/javascripts/Components/FilePreview/VideoPreview.tsx index 6951e6eccdf..61ec2c5a7dc 100644 --- a/packages/web/src/javascripts/Components/FilePreview/VideoPreview.tsx +++ b/packages/web/src/javascripts/Components/FilePreview/VideoPreview.tsx @@ -2,6 +2,7 @@ import { FilesController } from '@/Controllers/FilesController' import { NoPreviewIllustration } from '@standardnotes/icons' import { FileItem } from '@standardnotes/snjs' import { useState } from 'react' +import { c } from 'ttag' import Button from '../Button/Button' import { FileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction' @@ -26,9 +27,11 @@ const VideoPreview = ({ file, filesController, objectUrl, isEmbeddedInSuper }: P return (
-
This video can't be previewed.
+
{c('B7.FilesSubscriptionHelp.Files.Info') + .t`This video can't be previewed.`}
- To view this file, download it and open it using another application. + {c('B7.FilesSubscriptionHelp.Files.Info') + .t`To view this file, download it and open it using another application.`}
) diff --git a/packages/web/src/javascripts/Components/FileView/FileViewWithoutProtection.tsx b/packages/web/src/javascripts/Components/FileView/FileViewWithoutProtection.tsx index ae77848cccd..cef003abac3 100644 --- a/packages/web/src/javascripts/Components/FileView/FileViewWithoutProtection.tsx +++ b/packages/web/src/javascripts/Components/FileView/FileViewWithoutProtection.tsx @@ -14,6 +14,7 @@ import RoundIconButton from '../Button/RoundIconButton' import { useItemVaultInfo } from '@/Hooks/useItemVaultInfo' import Icon from '../Icon/Icon' import { VaultUserServiceEvent } from '@standardnotes/snjs' +import { c } from 'ttag' const SyncTimeoutNoDebounceMs = 100 const SyncTimeoutDebounceMs = 350 @@ -89,12 +90,16 @@ const FileViewWithoutProtection = ({ application, file }: FileViewProps) => { }, [addDragTarget, file, removeDragTarget, application.linkingController]) return ( -
+
{isReadonly && (
- This file is readonly + {c('B7.FilesSubscriptionHelp.Files.Info').t`This file is readonly`}
)}
{
{!isReadonly && } - +
)} {(this.state.outOfSync || this.state.showSyncResolution) && (
{this.state.outOfSync && (
- Potentially Out of Sync + {c('B2.NavSharedUI.Status').t`Potentially Out of Sync`}
)} {this.state.showSyncResolution && ( @@ -436,15 +445,15 @@ class Footer extends AbstractComponent { )} {this.state.offline && (
- Offline + {c('B2.NavSharedUI.Status').t`Offline`}
)} {this.state.hasPasscode && ( - +
diff --git a/packages/web/src/javascripts/Components/Footer/PreferencesButton.tsx b/packages/web/src/javascripts/Components/Footer/PreferencesButton.tsx index a6398bd86c9..48b624243c5 100644 --- a/packages/web/src/javascripts/Components/Footer/PreferencesButton.tsx +++ b/packages/web/src/javascripts/Components/Footer/PreferencesButton.tsx @@ -1,4 +1,5 @@ import { compareSemVersions, StatusServiceEvent } from '@standardnotes/snjs' +import { c } from 'ttag' import { keyboardStringForShortcut, OPEN_PREFERENCES_COMMAND } from '@standardnotes/ui-services' import { useCallback, useEffect, useMemo, useState } from 'react' import { useApplication } from '../ApplicationProvider' @@ -54,14 +55,19 @@ const PreferencesButton = ({ openPreferences }: Props) => { if (isMobileScreen) { return (
- +
) } return ( - +
) diff --git a/packages/web/src/javascripts/Components/Footer/VaultSelectionButton.tsx b/packages/web/src/javascripts/Components/Footer/VaultSelectionButton.tsx index 37e435af2da..fde4edf5c9c 100644 --- a/packages/web/src/javascripts/Components/Footer/VaultSelectionButton.tsx +++ b/packages/web/src/javascripts/Components/Footer/VaultSelectionButton.tsx @@ -1,5 +1,6 @@ import { classNames } from '@standardnotes/utils' import { useRef, useState } from 'react' +import { c } from 'ttag' import Icon from '../Icon/Icon' import Popover from '../Popover/Popover' import StyledTooltip from '../StyledTooltip/StyledTooltip' @@ -22,12 +23,12 @@ const VaultSelectionButton = ({ isMobileNavigation = false }: { isMobileNavigati return ( <> - + {isMobileNavigation ? ( ) : ( @@ -54,7 +55,7 @@ const VaultSelectionButton = ({ isMobileNavigation = false }: { isMobileNavigati )}
- - - + + +
{currentType === 'icon' && @@ -154,7 +170,7 @@ const IconPicker = ({ ) : ( handleEmojiChange(value)} />
- Use your keyboard to enter or paste in an emoji character. + {c('B4.Notes.EditingUI.Info').t`Use your keyboard to enter or paste in an emoji character.`}
{isMacOS && (
- On macOS: ⌘ + ⌃ + Space bar to bring up emoji picker. + {c('B4.Notes.EditingUI.Info').t`On macOS: ⌘ + ⌃ + Space bar to bring up emoji picker.`}
)} {isWindows && (
- On Windows: Windows key + . to bring up emoji picker. + {c('B4.Notes.EditingUI.Info').t`On Windows: Windows key + . to bring up emoji picker.`}
)} diff --git a/packages/web/src/javascripts/Components/ImportModal/ImportModal.tsx b/packages/web/src/javascripts/Components/ImportModal/ImportModal.tsx index 809ed88e4c7..83f57fd185f 100644 --- a/packages/web/src/javascripts/Components/ImportModal/ImportModal.tsx +++ b/packages/web/src/javascripts/Components/ImportModal/ImportModal.tsx @@ -50,7 +50,9 @@ const ImportModal = ({ importModalController }: { importModalController: ImportM disabled: !isReadyToImport || (addImportsToTag && !shouldCreateTag && !existingTagForImports), }, { - label: importSuccessOrError ? c('B1.Account.ImportExport.Action').t`Close` : c('B1.Account.ImportExport.Action').t`Cancel`, + label: importSuccessOrError + ? c('B1.Account.ImportExport.Action').t`Close` + : c('B1.Account.ImportExport.Action').t`Cancel`, type: 'cancel', onClick: close, mobileSlot: 'left', @@ -78,7 +80,12 @@ const ImportModal = ({ importModalController }: { importModalController: ImportM return ( - +
{!files.length && } {files.length > 0 && ( diff --git a/packages/web/src/javascripts/Components/ImportModal/ImportModalController.ts b/packages/web/src/javascripts/Components/ImportModal/ImportModalController.ts index 5224ebb1ab6..ef000304c7e 100644 --- a/packages/web/src/javascripts/Components/ImportModal/ImportModalController.ts +++ b/packages/web/src/javascripts/Components/ImportModal/ImportModalController.ts @@ -176,7 +176,8 @@ export class ImportModalController extends AbstractViewController { this.updateFile({ ...file, status: 'error', - error: error instanceof Error ? error : new Error(c('B1.Account.ImportExport.Error').t`Could not import file`), + error: + error instanceof Error ? error : new Error(c('B1.Account.ImportExport.Error').t`Could not import file`), }) console.error(error) } diff --git a/packages/web/src/javascripts/Components/ImportModal/ImportModalFileItem.tsx b/packages/web/src/javascripts/Components/ImportModal/ImportModalFileItem.tsx index c048458ff6b..d6e42a46ef7 100644 --- a/packages/web/src/javascripts/Components/ImportModal/ImportModalFileItem.tsx +++ b/packages/web/src/javascripts/Components/ImportModal/ImportModalFileItem.tsx @@ -189,7 +189,8 @@ const ImportModalFileItem = ({ c('B1.Account.ImportExport.Status').t`Could not auto-detect service. Please select manually.`} {file.status === 'parsing' && c('B1.Account.ImportExport.Status').t`Parsing...`} {file.status === 'importing' && c('B1.Account.ImportExport.Status').t`Importing...`} - {file.status === 'uploading-files' && c('B1.Account.ImportExport.Status').t`Uploading and embedding files...`} + {file.status === 'uploading-files' && + c('B1.Account.ImportExport.Status').t`Uploading and embedding files...`} {file.status === 'error' && file.error.message}
diff --git a/packages/web/src/javascripts/Components/ImportModal/InitialPage.tsx b/packages/web/src/javascripts/Components/ImportModal/InitialPage.tsx index 033be277994..6921e084e8d 100644 --- a/packages/web/src/javascripts/Components/ImportModal/InitialPage.tsx +++ b/packages/web/src/javascripts/Components/ImportModal/InitialPage.tsx @@ -28,7 +28,8 @@ const ImportModalInitialPage = ({ setFiles, selectFiles }: Props) => { setFiles(files) }} > -
{c('B1.Account.ImportExport.Info').t`Drag and drop files to auto-detect and import`}
+
{c('B1.Account.ImportExport.Info') + .t`Drag and drop files to auto-detect and import`}
{c('B1.Account.ImportExport.Info').t`Or click to open file picker`}
{c('B1.Account.ImportExport.Info').t`or import from:`}
diff --git a/packages/web/src/javascripts/Components/Input/DecoratedPasswordInput.tsx b/packages/web/src/javascripts/Components/Input/DecoratedPasswordInput.tsx index 38990b0e47a..725c34c9b30 100644 --- a/packages/web/src/javascripts/Components/Input/DecoratedPasswordInput.tsx +++ b/packages/web/src/javascripts/Components/Input/DecoratedPasswordInput.tsx @@ -1,4 +1,5 @@ import { Dispatch, FunctionComponent, Ref, SetStateAction, forwardRef, useState } from 'react' +import { c } from 'ttag' import DecoratedInput from './DecoratedInput' import IconButton from '@/Components/Button/IconButton' import { DecoratedInputProps } from './DecoratedInputProps' @@ -11,7 +12,7 @@ const Toggle: FunctionComponent<{ className="h-5 w-5 justify-center rounded-full p-0 text-neutral hover:bg-passive-4" icon={isToggled ? 'eye-off' : 'eye'} iconClassName="w-3.5 h-3.5" - title="Show/hide password" + title={c('B2.NavSharedUI.AriaLabel').t`Show/hide password`} onClick={() => setIsToggled((isToggled) => !isToggled)} focusable={true} /> diff --git a/packages/web/src/javascripts/Components/ItemSelectionDropdown/ItemSelectionDropdown.tsx b/packages/web/src/javascripts/Components/ItemSelectionDropdown/ItemSelectionDropdown.tsx index 1ec620c8bfe..1aa371a6535 100644 --- a/packages/web/src/javascripts/Components/ItemSelectionDropdown/ItemSelectionDropdown.tsx +++ b/packages/web/src/javascripts/Components/ItemSelectionDropdown/ItemSelectionDropdown.tsx @@ -1,4 +1,5 @@ import { doesItemMatchSearchQuery } from '@/Utils/Items/Search/doesItemMatchSearchQuery' +import { c } from 'ttag' import { Combobox, ComboboxItem, @@ -49,7 +50,7 @@ const ItemSelectionDropdown = ({ contentTypes, placeholder, onSelection, combobo return (
- Select an item + {c('B2.NavSharedUI.AriaLabel').t`Select an item`} )) ) : ( -
No results found
+
{c('B2.NavSharedUI.Info').t`No results found`}
)}
diff --git a/packages/web/src/javascripts/Components/KeyboardShortcutsHelpModal/KeyboardShortcutsHelpModal.tsx b/packages/web/src/javascripts/Components/KeyboardShortcutsHelpModal/KeyboardShortcutsHelpModal.tsx index 2fff24d5994..c7a8370b8b3 100644 --- a/packages/web/src/javascripts/Components/KeyboardShortcutsHelpModal/KeyboardShortcutsHelpModal.tsx +++ b/packages/web/src/javascripts/Components/KeyboardShortcutsHelpModal/KeyboardShortcutsHelpModal.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useMemo, useState } from 'react' +import { c } from 'ttag' import Modal, { ModalAction } from '../Modal/Modal' import ModalOverlay from '../Modal/ModalOverlay' import { @@ -9,23 +10,26 @@ import { } from '@standardnotes/ui-services' import { observer } from 'mobx-react-lite' import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/KeyboardShortcutIndicator' +import { + KEYBOARD_SHORTCUT_CATEGORY_ORDER, + translateKeyboardShortcutCategory, +} from '@/Utils/KeyboardShortcutCategoryLabels' -type GroupedItems = { - [category in KeyboardShortcutCategory]: KeyboardShortcutHelpItem[] -} +type GroupedItems = Record + +const createEmptyGroupedItems = (): GroupedItems => + Object.fromEntries( + KEYBOARD_SHORTCUT_CATEGORY_ORDER.map((category) => [category, [] as KeyboardShortcutHelpItem[]]), + ) as GroupedItems const createGroupedItems = (items: KeyboardShortcutHelpItem[]): GroupedItems => { - const groupedItems: GroupedItems = { - 'Current note': [], - Formatting: [], - 'Super notes': [], - 'Notes list': [], - General: [], + const groupedItems = createEmptyGroupedItems() + + for (const item of items) { + groupedItems[item.category].push(item) } - return items.reduce((acc, item) => { - acc[item.category].push(item) - return acc - }, groupedItems) + + return groupedItems } const Item = ({ item }: { item: KeyboardShortcutHelpItem }) => { @@ -49,7 +53,7 @@ const KeyboardShortcutsModal = ({ keyboardService }: { keyboardService: Keyboard return keyboardService.addCommandHandler({ command: TOGGLE_KEYBOARD_SHORTCUTS_MODAL, category: 'General', - description: 'Toggle keyboard shortcuts help', + description: c('B2.NavSharedUI.Action').t`Toggle keyboard shortcuts help`, onKeyDown: () => { setItems(createGroupedItems(keyboardService.getRegisteredKeyboardShorcutHelpItems())) setIsOpen((open) => !open) @@ -60,7 +64,7 @@ const KeyboardShortcutsModal = ({ keyboardService }: { keyboardService: Keyboard const actions = useMemo( (): ModalAction[] => [ { - label: 'Cancel', + label: c('B2.NavSharedUI.Action').t`Cancel`, onClick: close, type: 'cancel', mobileSlot: 'left', @@ -71,18 +75,24 @@ const KeyboardShortcutsModal = ({ keyboardService }: { keyboardService: Keyboard return ( - - {Object.entries(items).map( - ([category, items]) => - items.length > 0 && ( -
-
{category}
- {items.map((item, index) => ( - - ))} + + {KEYBOARD_SHORTCUT_CATEGORY_ORDER.map((category) => { + const categoryItems = items[category] + if (categoryItems.length === 0) { + return null + } + + return ( +
+
+ {translateKeyboardShortcutCategory(category)}
- ), - )} + {categoryItems.map((item, index) => ( + + ))} +
+ ) + })}
) diff --git a/packages/web/src/javascripts/Components/LinkedItems/ItemLinkAutocompleteInput.tsx b/packages/web/src/javascripts/Components/LinkedItems/ItemLinkAutocompleteInput.tsx index de72cb6df8f..abf959e4a9b 100644 --- a/packages/web/src/javascripts/Components/LinkedItems/ItemLinkAutocompleteInput.tsx +++ b/packages/web/src/javascripts/Components/LinkedItems/ItemLinkAutocompleteInput.tsx @@ -14,6 +14,7 @@ import { ElementIds } from '@/Constants/ElementIDs' import { getLinkingSearchResults } from '@/Utils/Items/Search/getSearchResults' import { useApplication } from '../ApplicationProvider' import { DecryptedItem, SNNote } from '@standardnotes/snjs' +import { c } from 'ttag' import { Combobox, ComboboxItem, ComboboxPopover, useComboboxStore, VisuallyHidden } from '@ariakit/react' import LinkedItemMeta from './LinkedItemMeta' import { LinkedItemSearchResultsAddTagOption } from './LinkedItemSearchResultsAddTagOption' @@ -85,10 +86,10 @@ const ItemLinkAutocompleteInput = forwardRef(