diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..13e044a
--- /dev/null
+++ b/.env.example
@@ -0,0 +1 @@
+LOCIZE_API_KEY=
diff --git a/.gitignore b/.gitignore
index f691227..e9d8978 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,5 @@ yarn-error.log*
dist.zip
.aider*
.qodo
+
+error.txt
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 3f79c3d..7c01f00 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,12 +4,11 @@
-
+
-
-
-
-
+
+
+
@@ -42,171 +41,178 @@
"state": "OPEN"
}
}
- {
+ "prStates": [
{
- "id": {
- "id": "PR_kwDOMJIfts51PkS9",
- "number": 22
+ "id": {
+ "id": "PR_kwDOMJIfts51PkS9",
+ "number": 22
},
- "lastSeen": 1741207144695
+ "lastSeen": 1741207144695
},
{
- "id": {
- "id": "PR_kwDOMJIfts6NiNYl",
- "number": 32
+ "id": {
+ "id": "PR_kwDOMJIfts6NiNYl",
+ "number": 32
},
- "lastSeen": 1741209723869
+ "lastSeen": 1741209723869
},
{
- "id": {
- "id": "PR_kwDOMJIfts6Nheyd",
- "number": 31
+ "id": {
+ "id": "PR_kwDOMJIfts6Nheyd",
+ "number": 31
},
- "lastSeen": 1741213371410
+ "lastSeen": 1741213371410
},
{
- "id": {
- "id": "PR_kwDOMJIfts6NmRBs",
- "number": 33
+ "id": {
+ "id": "PR_kwDOMJIfts6NmRBs",
+ "number": 33
},
- "lastSeen": 1741282429036
+ "lastSeen": 1741282429036
},
{
- "id": {
- "id": "PR_kwDOMJIfts5zyFTs",
- "number": 15
+ "id": {
+ "id": "PR_kwDOMJIfts5zyFTs",
+ "number": 15
},
- "lastSeen": 1741535540953
+ "lastSeen": 1741535540953
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QQB3c",
- "number": 59
+ "id": {
+ "id": "PR_kwDOMJIfts6QQB3c",
+ "number": 59
},
- "lastSeen": 1743018960900
+ "lastSeen": 1743018960900
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QMPEg",
- "number": 58
+ "id": {
+ "id": "PR_kwDOMJIfts6QMPEg",
+ "number": 58
},
- "lastSeen": 1743019452983
+ "lastSeen": 1743019452983
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QZvRI",
- "number": 61
+ "id": {
+ "id": "PR_kwDOMJIfts6QZvRI",
+ "number": 61
},
- "lastSeen": 1743103196866
+ "lastSeen": 1743103196866
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QqPrQ",
- "number": 73
+ "id": {
+ "id": "PR_kwDOMJIfts6QqPrQ",
+ "number": 73
},
- "lastSeen": 1743265865001
+ "lastSeen": 1743265865001
},
{
- "id": {
- "id": "PR_kwDOMJIfts6Qp5nI",
- "number": 72
+ "id": {
+ "id": "PR_kwDOMJIfts6Qp5nI",
+ "number": 72
},
- "lastSeen": 1743338472110
+ "lastSeen": 1743338472110
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QsjlS",
- "number": 76
+ "id": {
+ "id": "PR_kwDOMJIfts6QsjlS",
+ "number": 76
},
- "lastSeen": 1743352150953
+ "lastSeen": 1743352150953
},
{
- "id": {
- "id": "PR_kwDOMJIfts6Q0JBe",
- "number": 82
+ "id": {
+ "id": "PR_kwDOMJIfts6Q0JBe",
+ "number": 82
},
- "lastSeen": 1743470267269
+ "lastSeen": 1743470267269
},
{
- "id": {
- "id": "PR_kwDOMJIfts6UE9-x",
- "number": 102
+ "id": {
+ "id": "PR_kwDOMJIfts6UE9-x",
+ "number": 102
},
- "lastSeen": 1747171977348
+ "lastSeen": 1747171977348
},
{
- "id": {
- "id": "PR_kwDOMJIfts6XPua_",
- "number": 117
+ "id": {
+ "id": "PR_kwDOMJIfts6XPua_",
+ "number": 117
},
- "lastSeen": 1747929835864
+ "lastSeen": 1747929835864
},
{
- "id": {
- "id": "PR_kwDOMJIfts6XY-mZ",
- "number": 119
+ "id": {
+ "id": "PR_kwDOMJIfts6XY-mZ",
+ "number": 119
},
- "lastSeen": 1748028108508
+ "lastSeen": 1748028108508
},
{
- "id": {
- "id": "PR_kwDOMJIfts6Xdz4n",
- "number": 120
+ "id": {
+ "id": "PR_kwDOMJIfts6Xdz4n",
+ "number": 120
},
- "lastSeen": 1748282672214
+ "lastSeen": 1748282672214
},
{
- "id": {
- "id": "PR_kwDOMJIfts6X_zxl",
- "number": 131
+ "id": {
+ "id": "PR_kwDOMJIfts6X_zxl",
+ "number": 131
},
- "lastSeen": 1748881279494
+ "lastSeen": 1748881279494
},
{
- "id": {
- "id": "PR_kwDOMJIfts6bhieT",
- "number": 152
+ "id": {
+ "id": "PR_kwDOMJIfts6bhieT",
+ "number": 152
},
- "lastSeen": 1751848489082
+ "lastSeen": 1751848489082
},
{
- "id": {
- "id": "PR_kwDOMJIfts6dOyRk",
- "number": 154
+ "id": {
+ "id": "PR_kwDOMJIfts6dOyRk",
+ "number": 154
},
- "lastSeen": 1751849436454
+ "lastSeen": 1751849436454
},
{
- "id": {
- "id": "PR_kwDOMJIfts6cHjNi",
- "number": 153
+ "id": {
+ "id": "PR_kwDOMJIfts6cHjNi",
+ "number": 153
},
- "lastSeen": 1751849501498
+ "lastSeen": 1751849501498
},
{
- "id": {
- "id": "PR_kwDOMJIfts6Zs1FN",
- "number": 145
+ "id": {
+ "id": "PR_kwDOMJIfts6Zs1FN",
+ "number": 145
},
- "lastSeen": 1751849770308
+ "lastSeen": 1751849770308
},
{
- "id": {
- "id": "PR_kwDOMJIfts6bgKi9",
- "number": 150
+ "id": {
+ "id": "PR_kwDOMJIfts6bgKi9",
+ "number": 150
},
- "lastSeen": 1751850367300
+ "lastSeen": 1751850367300
},
{
- "id": {
- "id": "PR_kwDOMJIfts6eUKC-",
- "number": 176
+ "id": {
+ "id": "PR_kwDOMJIfts6eUKC-",
+ "number": 176
},
- "lastSeen": 1752158748013
+ "lastSeen": 1752158748013
+ },
+ {
+ "id": {
+ "id": "PR_kwDOMJIfts6eqzP7",
+ "number": 190
+ },
+ "lastSeen": 1752404173008
}
]
-}]]>
+}
{
"selectedUrlAndAccountId": {
"url": "https://github.com/iib0011/omni-tools.git",
@@ -244,6 +250,9 @@
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
"Docker.Dockerfile build.executor": "Run",
"Docker.Dockerfile.executor": "Run",
+ "Node.js.add-i18n-to-meta.js.executor": "Run",
+ "Node.js.locize-upload.js.executor": "Run",
+ "Node.js.update-i18n-from-meta.js.executor": "Run",
"Playwright.Create transparent PNG.should make png color transparent.executor": "Run",
"Playwright.JoinText Component.executor": "Run",
"Playwright.JoinText Component.should merge text pieces with specified join character.executor": "Run",
@@ -252,6 +261,7 @@
"RunOnceActivity.git.unshallow": "true",
"Vitest.compute function (1).executor": "Run",
"Vitest.compute function.executor": "Run",
+ "Vitest.generatePassword.executor": "Run",
"Vitest.mergeText.executor": "Run",
"Vitest.mergeText.should merge lines and preserve blank lines when deleteBlankLines is false.executor": "Run",
"Vitest.mergeText.should merge lines, preserve blank lines and trailing spaces when both deleteBlankLines and deleteTrailingSpaces are false.executor": "Run",
@@ -262,10 +272,10 @@
"Vitest.replaceText function (regexp mode).should return the original text when passed an invalid regexp.executor": "Run",
"Vitest.replaceText function.executor": "Run",
"Vitest.timeBetweenDates.executor": "Run",
- "git-widget-placeholder": "main",
+ "git-widget-placeholder": "#190 on fork/AshAnand34/en-hi-translation",
"ignore.virus.scanning.warn.message": "true",
"kotlin-language-version-configured": "true",
- "last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools/public",
+ "last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
@@ -273,6 +283,9 @@
"nodejs_package_manager_path": "npm",
"npm.build.executor": "Run",
"npm.dev.executor": "Run",
+ "npm.i18n:pull.executor": "Run",
+ "npm.i18n:push.executor": "Run",
+ "npm.i18n:sync.executor": "Run",
"npm.lint.executor": "Run",
"npm.prebuild.executor": "Run",
"npm.script:create:tool.executor": "Run",
@@ -299,58 +312,31 @@
+
+
-
-
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -367,33 +353,58 @@
-
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
-
-
-
+
-
-
-
-
+
+
+
+
@@ -504,126 +515,9 @@
-
-
-
- 1743022260639
-
-
-
- 1743022260639
-
-
-
- 1743051792459
-
-
-
- 1743051792459
-
-
-
- 1743052111988
-
-
-
- 1743052111988
-
-
-
- 1743106796406
-
-
-
- 1743106796406
-
-
-
- 1743349732644
-
-
-
- 1743349732644
-
-
-
- 1743355099396
-
-
-
- 1743355099396
-
-
-
- 1743355166425
-
-
-
- 1743355166426
-
-
-
- 1743385388051
-
-
-
- 1743385388051
-
-
-
- 1743385467178
-
-
-
- 1743385467178
-
-
-
- 1743385898871
-
-
-
- 1743385898871
-
-
-
- 1743459110471
-
-
-
- 1743459110471
-
-
-
- 1743459205311
-
-
-
- 1743459205311
-
-
-
- 1743470832619
-
-
-
- 1743470832619
-
-
-
- 1743644598841
-
-
-
- 1743644598841
-
-
-
- 1743644703041
-
-
-
- 1743644703042
+
+
+
@@ -897,7 +791,127 @@
1752158119802
-
+
+
+ 1752402313190
+
+
+
+ 1752402313191
+
+
+
+ 1752408068771
+
+
+
+ 1752408068771
+
+
+
+ 1752412149075
+
+
+
+ 1752412149075
+
+
+
+ 1752422405814
+
+
+
+ 1752422405814
+
+
+
+ 1752423460080
+
+
+
+ 1752423460080
+
+
+
+ 1752493634215
+
+
+
+ 1752493634215
+
+
+
+ 1752497705915
+
+
+
+ 1752497705915
+
+
+
+ 1752501110885
+
+
+
+ 1752501110885
+
+
+
+ 1752503206380
+
+
+
+ 1752503206380
+
+
+
+ 1752503720380
+
+
+
+ 1752503720380
+
+
+
+ 1752503770543
+
+
+
+ 1752503770543
+
+
+
+ 1752505593881
+
+
+
+ 1752505593881
+
+
+
+ 1752512678963
+
+
+
+ 1752512678963
+
+
+
+ 1752514466233
+
+
+
+ 1752514466233
+
+
+
+ 1752515675314
+
+
+
+ 1752515675314
+
+
@@ -944,19 +958,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -969,7 +970,20 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
false
diff --git a/@types/i18n.d.ts b/@types/i18n.d.ts
new file mode 100644
index 0000000..efd6ca1
--- /dev/null
+++ b/@types/i18n.d.ts
@@ -0,0 +1,9 @@
+// types/i18next.d.ts
+import 'i18next';
+import { resources } from '../src/i18n';
+
+declare module 'i18next' {
+ interface CustomTypeOptions {
+ resources: (typeof resources)['en'];
+ }
+}
diff --git a/README.md b/README.md
index 9d6e367..ed6f0b9 100644
--- a/README.md
+++ b/README.md
@@ -30,21 +30,21 @@ Here is the [demo](https://omnitools.app) website.
All files are processed entirely on the client side: nothing ever leaves your device.
Plus, the Docker image is super lightweight at just 28MB, making it fast to deploy and easy to self-host.
-
+
## Table of Contents
- [Features](#features)
- [Self-host](#self-hostrun)
- [Contribute](#contribute)
-- [License](#license)
- [Contact](#contact)
+- [License](#license)
## Features
We strive to offer a variety of tools, including:
-## **Image/Video/Audio Tools**
+### **Image/Video/Audio Tools**
- Image Resizer
- Image Converter
@@ -53,33 +53,33 @@ We strive to offer a variety of tools, including:
- Video Reverser
- And more...
-## **PDF Tools**
+### **PDF Tools**
- PDF Splitter
- PDF Merger
- PDF Editor
- And more...
-## **Text/List Tools**
+### **Text/List Tools**
- Case Converters
- List Shuffler
- Text Formatters
- And more...
-## **Date and Time Tools**
+### **Date and Time Tools**
- Date Calculators
- Time Zone Converters
- And more...
-## **Math Tools**
+### **Math Tools**
- Generate Prime Numbers
- Calculate voltage, current, or resistance
- And more...
-## **Data Tools**
+### **Data Tools**
- JSON Tools
- CSV Tools
@@ -148,20 +148,34 @@ npm run test
npm run test:e2e
```
+### i18n (Translations)
+The translation files are [here](public/locales). Only edit these if you are a developer. For non developers, use [Locize](https://www.locize.app/register?invitation=YOIH0Dyz3KHh3uQFCGYe9v1QOUoq8W5ySgmlwjX9cSypeJmt8F40brDtVbXb71fK).
+
## ЁЯдЭ Looking to contribute?
We welcome contributions! You can help by:
-- тЬЕ Reporting bugs
-- тЬЕ Suggesting new features in GitHub issues or [here](https://tally.so/r/nrkkx2)
-- тЬЕ Improving documentation
-- тЬЕ Submitting pull requests
+- Reporting bugs
+- Suggesting new features in GitHub issues or [here](https://tally.so/r/nrkkx2)
+- Translating in [Locize project](https://www.locize.app/register?invitation=YOIH0Dyz3KHh3uQFCGYe9v1QOUoq8W5ySgmlwjX9cSypeJmt8F40brDtVbXb71fK).
+- Improving documentation
+- Submitting pull requests
+
You can also join our [Discord server](https://discord.gg/SDbbn3hT4b)
+## ЁЯзб Sponsors
+
-### Contributors
+Thanks to [Locize](https://www.locize.com) for sponsoring OmniTools and supporting localization efforts.
+They make translation management simple and developer-friendly.
+
+## Contributors
diff --git a/img.png b/docs-images/img.png
similarity index 100%
rename from img.png
rename to docs-images/img.png
diff --git a/docs-images/locizeSponsor.svg b/docs-images/locizeSponsor.svg
new file mode 100644
index 0000000..1139aa2
--- /dev/null
+++ b/docs-images/locizeSponsor.svg
@@ -0,0 +1,187 @@
+
+
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 5b698c2..cc72c78 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,7 @@
"@types/lodash": "^4.17.5",
"@types/morsee": "^1.0.2",
"@types/omggif": "^1.0.5",
+ "@types/react-i18next": "^7.8.3",
"browser-image-compression": "^2.0.2",
"buffer": "^6.0.3",
"color": "^4.2.3",
@@ -32,10 +33,13 @@
"dayjs": "^1.11.13",
"fast-xml-parser": "^5.2.5",
"formik": "^2.4.6",
+ "i18next": "^25.3.2",
+ "i18next-http-backend": "^3.0.2",
"jimp": "^0.22.12",
"js-quantities": "^1.8.0",
"jszip": "^3.10.1",
"lint-staged": "^15.4.3",
+ "locize": "^4.0.14",
"lodash": "^4.17.21",
"mime": "^4.0.6",
"morsee": "^1.0.9",
@@ -51,6 +55,7 @@
"react-dom": "^18.3.1",
"react-filerobot-image-editor": "^4.9.1",
"react-helmet": "^6.1.0",
+ "react-i18next": "^15.6.0",
"react-image-crop": "^11.0.7",
"react-konva": "^18.2.10",
"react-router-dom": "^6.23.1",
@@ -85,6 +90,8 @@
"eslint-plugin-tailwindcss": "^3.17.0",
"happy-dom": "^12.10.3",
"husky": "^9.0.11",
+ "i18next-locize-backend": "^7.0.4",
+ "locize-cli": "^10.1.1",
"postcss": "^8.4.38",
"prettier": "3.1.1",
"start-server-and-test": "^2.0.4",
@@ -302,12 +309,10 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz",
- "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==",
- "dependencies": {
- "regenerator-runtime": "^0.14.0"
- },
+ "version": "7.27.6",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
+ "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
+ "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
@@ -1419,20 +1424,22 @@
}
},
"node_modules/@floating-ui/core": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz",
- "integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==",
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz",
+ "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==",
+ "license": "MIT",
"dependencies": {
- "@floating-ui/utils": "^0.2.0"
+ "@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/dom": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz",
- "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==",
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz",
+ "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==",
+ "license": "MIT",
"dependencies": {
- "@floating-ui/core": "^1.0.0",
- "@floating-ui/utils": "^0.2.0"
+ "@floating-ui/core": "^1.7.2",
+ "@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/react-dom": {
@@ -1448,9 +1455,21 @@
}
},
"node_modules/@floating-ui/utils": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
- "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
+ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
+ "license": "MIT"
+ },
+ "node_modules/@fluent/syntax": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/@fluent/syntax/-/syntax-0.19.0.tgz",
+ "integrity": "sha512-5D2qVpZrgpjtqU4eNOcWGp1gnUCgjfM+vKGE2y03kKN6z5EBhtx0qdRFbg8QuNNj8wXNoX93KJoYb+NqoxswmQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=14.0.0",
+ "npm": ">=7.0.0"
+ }
},
"node_modules/@hapi/hoek": {
"version": "9.3.0",
@@ -2078,6 +2097,13 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@js.properties/properties": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/@js.properties/properties/-/properties-0.5.4.tgz",
+ "integrity": "sha512-4M/Mb2CxzuI1CtQhVFs6OC9ceuGPAP6SOWnpLcrdB1TcUHroXbsYDVJNOm32koRMfuCoRACbojcm4dPPcQxu0w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@mui/base": {
"version": "5.0.0-beta.40",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz",
@@ -3395,6 +3421,12 @@
"hoist-non-react-statics": "^3.3.0"
}
},
+ "node_modules/@types/i18next": {
+ "version": "12.1.0",
+ "resolved": "https://registry.npmjs.org/@types/i18next/-/i18next-12.1.0.tgz",
+ "integrity": "sha512-qLyqTkp3ZKHsSoX8CNVYcTyTkxlm0aRCUpaUVetgkSlSpiNCdWryOgaYwgbO04tJIfLgBXPcy0tJ3Nl/RagllA==",
+ "license": "MIT"
+ },
"node_modules/@types/js-quantities": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/@types/js-quantities/-/js-quantities-1.6.6.tgz",
@@ -3484,6 +3516,16 @@
"@types/react": "*"
}
},
+ "node_modules/@types/react-i18next": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@types/react-i18next/-/react-i18next-7.8.3.tgz",
+ "integrity": "sha512-VPopxbHXz/1Sjl+ljXQQchf6FHXaYLaH0a6TH6KnGOQGD4LzNbUVlofK26S30OIYfYibm8r/sAb2KeTst+AwTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/i18next": "*",
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/react-reconciler": {
"version": "0.28.9",
"resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz",
@@ -3936,6 +3978,16 @@
"node": ">=0.4.0"
}
},
+ "node_modules/agent-base": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -3952,6 +4004,17 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/android-string-resource": {
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/android-string-resource/-/android-string-resource-2.3.10.tgz",
+ "integrity": "sha512-Ldzy2znjm+BVWVHbzyhmdiznVdIum/EM2CMtSPjnoVr1/MljZTVPB08giSpm1WIo00fK/sL/kcnvr0+d9wVUzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "rdotjson": "1.1.1",
+ "xml-js": "1.6.11"
+ }
+ },
"node_modules/ansi-escapes": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
@@ -4191,6 +4254,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/arrify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
+ "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/assertion-error": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
@@ -4200,6 +4273,13 @@
"node": "*"
}
},
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -4348,6 +4428,13 @@
"integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==",
"license": "MIT"
},
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -4450,6 +4537,16 @@
"node": ">=8"
}
},
+ "node_modules/cacheable-lookup": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz",
+ "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.6.0"
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
@@ -4577,6 +4674,46 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/cheerio": {
+ "version": "1.0.0-rc.12",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+ "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1",
+ "htmlparser2": "^8.0.1",
+ "parse5": "^7.0.0",
+ "parse5-htmlparser2-tree-adapter": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
+ "node_modules/cheerio-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+ "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-select": "^5.1.0",
+ "css-what": "^6.1.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -4802,6 +4939,16 @@
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"license": "MIT"
},
+ "node_modules/colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -4845,6 +4992,16 @@
"integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==",
"dev": true
},
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/conventional-changelog-angular": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz",
@@ -4936,10 +5093,21 @@
"cronstrue": "bin/cli.js"
}
},
+ "node_modules/cross-fetch": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz",
+ "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "node-fetch": "^2.7.0"
+ }
+ },
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -4959,6 +5127,23 @@
"node": ">=4"
}
},
+ "node_modules/css-select": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
+ "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/css-to-react-native": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
@@ -4971,6 +5156,19 @@
"postcss-value-parser": "^4.0.2"
}
},
+ "node_modules/css-what": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+ "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/css.escape": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
@@ -4994,6 +5192,13 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
+ "node_modules/csvjson": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/csvjson/-/csvjson-5.1.0.tgz",
+ "integrity": "sha512-OqALQHA0k2rEGluOWikwFq5qtkRUDyoWP2u0UJy8uFjFx5FPMjPzx7D2Hn2KjBLpc8jkGrT9HDNgTUfopDlqVg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/dargs": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz",
@@ -5203,6 +5408,16 @@
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
"dev": true
},
+ "node_modules/diff": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
+ "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/diff-sequences": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
@@ -5263,11 +5478,70 @@
"csstype": "^3.0.2"
}
},
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
"node_modules/dom-walk": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
},
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
"node_modules/dot-prop": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
@@ -5280,6 +5554,19 @@
"node": ">=8"
}
},
+ "node_modules/dotenv": {
+ "version": "16.5.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
+ "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
@@ -5304,6 +5591,16 @@
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
+ "node_modules/encoding": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+ "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "^0.6.2"
+ }
+ },
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
@@ -6108,6 +6405,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/flat": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "bin": {
+ "flat": "cli.js"
+ }
+ },
"node_modules/flat-cache": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
@@ -6135,6 +6442,16 @@
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true
},
+ "node_modules/fluent_conv": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/fluent_conv/-/fluent_conv-3.3.0.tgz",
+ "integrity": "sha512-OsTQyVWo1WYmEnnH7m3MRlk5NQq/+jXOLzv0WOk8GGn99LdQV1kNp3IOR6HYb+fwDqYebLPLAThS2pFEaDbyHQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@fluent/syntax": "0.19.0"
+ }
+ },
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
@@ -6368,6 +6685,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/gettext-converter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/gettext-converter/-/gettext-converter-1.3.0.tgz",
+ "integrity": "sha512-vXjx4vRBjw6rd3Zg73IMyNLZuPjs8/lE9gJZs270YJJI0t5vlCpdsyX5E0TmSd+KcRWzwPbwjwd6bnNpF72sFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "arrify": "^2.0.1",
+ "content-type": "1.0.5",
+ "encoding": "0.1.13"
+ }
+ },
"node_modules/gifwrap": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz",
@@ -6684,6 +7013,49 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "node_modules/html-parse-stringify": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
+ "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+ "license": "MIT",
+ "dependencies": {
+ "void-elements": "3.1.0"
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+ "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+ "dev": true,
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1",
+ "entities": "^4.4.0"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/human-signals": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
@@ -6707,11 +7079,79 @@
"url": "https://github.com/sponsors/typicode"
}
},
+ "node_modules/i18next": {
+ "version": "25.3.2",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.3.2.tgz",
+ "integrity": "sha512-JSnbZDxRVbphc5jiptxr3o2zocy5dEqpVm9qCGdJwRNO+9saUJS0/u4LnM/13C23fUEWxAylPqKU/NpMV/IjqA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://locize.com"
+ },
+ {
+ "type": "individual",
+ "url": "https://locize.com/i18next.html"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.27.6"
+ },
+ "peerDependencies": {
+ "typescript": "^5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/i18next-http-backend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.2.tgz",
+ "integrity": "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==",
+ "license": "MIT",
+ "dependencies": {
+ "cross-fetch": "4.0.0"
+ }
+ },
+ "node_modules/i18next-http-backend/node_modules/cross-fetch": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
+ "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
+ "license": "MIT",
+ "dependencies": {
+ "node-fetch": "^2.6.12"
+ }
+ },
+ "node_modules/i18next-locize-backend": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/i18next-locize-backend/-/i18next-locize-backend-7.0.4.tgz",
+ "integrity": "sha512-saRyIQAX0k+YA6XzirU6cyudWDj1W7bGDz/Szq+8OIs3JJnNuMZCADuNgCwmo+dQm9P69bbALymV+9t9ffywBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cross-fetch": "4.1.0"
+ }
+ },
+ "node_modules/i18next-subliminal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/i18next-subliminal/-/i18next-subliminal-1.0.1.tgz",
+ "integrity": "sha512-h3m1oQ8lTaTNNgqmvBXAzFSGoJ0uobUcFW6TJMaWV4QDQ0+YGIih3ZcCX1XouGzK8yyFX13lP+2zAT/k7u4oiQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.27.0"
+ }
+ },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
@@ -7594,6 +8034,16 @@
"license": "MIT",
"peer": true
},
+ "node_modules/laravelphp": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/laravelphp/-/laravelphp-2.0.4.tgz",
+ "integrity": "sha512-rx5X+Yds6MmIxGS+VVQBWhylPYxkOYmKXrWqQHc2rj2ewsoWMZS7OaTXk9UE8y95XV+D5CqLjaEj+IJgRmrIaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "php-parser": "3.1.5"
+ }
+ },
"node_modules/lazy-ass": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
@@ -7876,6 +8326,146 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/locize": {
+ "version": "4.0.14",
+ "resolved": "https://registry.npmjs.org/locize/-/locize-4.0.14.tgz",
+ "integrity": "sha512-4AnM9Hoxm7tgE+LhkdX1cDp+PLnraSruNc/3O/AAFfbmqmqaGdf9TyLwgHd0C9ug6GPRS0RIzXH6wdg5tHMWWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.23.6",
+ "@floating-ui/dom": "^1.6.13",
+ "i18next-subliminal": "^1.0.1"
+ }
+ },
+ "node_modules/locize-cli": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/locize-cli/-/locize-cli-10.1.1.tgz",
+ "integrity": "sha512-X0qzyKvlMPsu65jSFAaTLGobVFvLvd2wuPqPiJqROruneIc2ddEIRA6jspuRBpi9EGxDCERnmkM5nkGK/SjV8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@js.properties/properties": "0.5.4",
+ "android-string-resource": "2.3.10",
+ "async": "3.2.6",
+ "cacheable-lookup": "6.1.0",
+ "colors": "1.4.0",
+ "commander": "9.5.0",
+ "csvjson": "5.1.0",
+ "diff": "7.0.0",
+ "dotenv": "16.5.0",
+ "flat": "5.0.2",
+ "fluent_conv": "3.3.0",
+ "gettext-converter": "1.3.0",
+ "https-proxy-agent": "7.0.6",
+ "ini": "4.1.3",
+ "laravelphp": "2.0.4",
+ "locize-xcstrings": "2.0.0",
+ "lodash.clonedeep": "4.5.0",
+ "mkdirp": "3.0.1",
+ "node-fetch": "2.7.0",
+ "resx": "2.0.4",
+ "rimraf": "4.4.1",
+ "strings-file": "0.0.5",
+ "tmexchange": "2.0.5",
+ "xliff": "6.2.2",
+ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
+ "yaml": "2.8.0"
+ },
+ "bin": {
+ "locize": "bin/locize"
+ }
+ },
+ "node_modules/locize-cli/node_modules/commander": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
+ "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || >=14"
+ }
+ },
+ "node_modules/locize-cli/node_modules/glob": {
+ "version": "9.3.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz",
+ "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "minimatch": "^8.0.2",
+ "minipass": "^4.2.4",
+ "path-scurry": "^1.6.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/locize-cli/node_modules/ini": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz",
+ "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/locize-cli/node_modules/minimatch": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz",
+ "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/locize-cli/node_modules/minipass": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
+ "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/locize-cli/node_modules/rimraf": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz",
+ "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^9.2.0"
+ },
+ "bin": {
+ "rimraf": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/locize-xcstrings": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locize-xcstrings/-/locize-xcstrings-2.0.0.tgz",
+ "integrity": "sha512-Gef3IrMDSB5ZuRbym9ktr7KXCTFjIvs1T2TEnaew5ed7BBwt3od0/sj8C7X9iGpRebHxG1kyF6hR6aK8iBPkLg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -7892,6 +8482,13 @@
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
"dev": true
},
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
@@ -8277,6 +8874,22 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/mkdirp": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+ "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/mlly": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz",
@@ -8457,6 +9070,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -8592,6 +9218,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/obop": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/obop/-/obop-0.2.3.tgz",
+ "integrity": "sha512-xmaHk+pwv4T6QKoq553KeJlkZUV6WBVGU/dO7rppA7YFIvGf+xB1OQAkw8mcORtxtSHpiK5JiTQ+d7Bme/Y7Wg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/omggif": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz",
@@ -8771,6 +9404,46 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/parse5": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+ "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "entities": "^6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-htmlparser2-tree-adapter": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
+ "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "domhandler": "^5.0.3",
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5/node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -8897,6 +9570,13 @@
"integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."
},
+ "node_modules/php-parser": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/php-parser/-/php-parser-3.1.5.tgz",
+ "integrity": "sha512-jEY2DcbgCm5aclzBdfW86GM6VEIWcSlhTBSHN1qhJguVePlYe28GhwS0yoeLYXpM2K8y6wzLwrbq814n2PHSoQ==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -9282,6 +9962,16 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
+ "node_modules/process.argv": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/process.argv/-/process.argv-0.6.1.tgz",
+ "integrity": "sha512-WQOWF/VB0pTJu7c3ko0y5w6HWDQf6Wm3ppvKDI7ET4OSYBDOvcliBRM1HFIHHkJPNa/1bYTzmUinjF8492oaBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "obop": "^0.2.2"
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -9579,6 +10269,34 @@
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"license": "MIT"
},
+ "node_modules/rdotjson": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/rdotjson/-/rdotjson-1.1.1.tgz",
+ "integrity": "sha512-L6wBhp64fAr/FPhjfkuf9Lx6dAbfkznROcBMj55tVamw6ddTvhcgoqu89a3lUJCaALJkZe/mTcQoNM0P09RpQg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cheerio": "1.0.0-rc.12",
+ "is-stream": "^2.0.0",
+ "process.argv": "^0.6.1"
+ },
+ "bin": {
+ "rdotjson": "rdotjson.cli.js"
+ }
+ },
+ "node_modules/rdotjson/node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@@ -9682,6 +10400,32 @@
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
},
+ "node_modules/react-i18next": {
+ "version": "15.6.0",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.6.0.tgz",
+ "integrity": "sha512-W135dB0rDfiFmbMipC17nOhGdttO5mzH8BivY+2ybsQBbXvxWIwl3cmeH3T9d+YPBSJu/ouyJKFJTtkK7rJofw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.27.6",
+ "html-parse-stringify": "^3.0.1"
+ },
+ "peerDependencies": {
+ "i18next": ">= 23.2.3",
+ "react": ">= 16.8.0",
+ "typescript": "^5"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-image-crop": {
"version": "11.0.7",
"resolved": "https://registry.npmjs.org/react-image-crop/-/react-image-crop-11.0.7.tgz",
@@ -9880,11 +10624,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/regenerator-runtime": {
- "version": "0.14.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
- "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
- },
"node_modules/regexp.prototype.flags": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
@@ -9982,6 +10721,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/resx": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/resx/-/resx-2.0.4.tgz",
+ "integrity": "sha512-b3IW7ge0nxbWOhbUGO/WULL4NG5ctrpey+UgDIwRq5K4Bblna4t1hLMbA2DZC9Y6e8U/zLuRJHg+qEOVKOoypQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "xml2js": "0.5.0"
+ }
+ },
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -10139,7 +10888,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
+ "devOptional": true
},
"node_modules/sax": {
"version": "1.4.1",
@@ -10706,6 +11455,29 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/strings-file": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/strings-file/-/strings-file-0.0.5.tgz",
+ "integrity": "sha512-4/Fc8WshjKl/6MctVvdcdH3pQpbSP3J481hMUo9qMSpEK+piDYKYg8oSTGGKFMt2AyeZCQCnGF1uMq3i/xg/wQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "^0.4.13"
+ }
+ },
+ "node_modules/strings-file/node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -11140,6 +11912,16 @@
"@popperjs/core": "^2.9.0"
}
},
+ "node_modules/tmexchange": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/tmexchange/-/tmexchange-2.0.5.tgz",
+ "integrity": "sha512-fJQcBIY/ebEYDagOA0IY2PKYs2OJtBo0UGO+O2huyTkL9h+1Fg75DKw0JHkzXA1C56ejQdLW7S9YS/IL9rOpmQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "xml2js": "0.5.0"
+ }
+ },
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -11347,7 +12129,7 @@
"version": "5.4.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
- "dev": true,
+ "devOptional": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -11631,6 +12413,15 @@
}
}
},
+ "node_modules/void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/wait-on": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz",
@@ -11940,6 +12731,42 @@
"xtend": "^4.0.0"
}
},
+ "node_modules/xliff": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/xliff/-/xliff-6.2.2.tgz",
+ "integrity": "sha512-8j1NITWDF3oRV3wkE514g1yYpk9pv3MKiOrVVaxY8YWtcQs1Ux12tfVmIwKeP5/GVfS7g0N6oRm1TqjR2MeEaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "xml-js": "1.6.11"
+ }
+ },
+ "node_modules/xlsx": {
+ "version": "0.20.3",
+ "resolved": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
+ "integrity": "sha512-oLDq3jw7AcLqKWH2AhCpVTZl8mf6X2YReP+Neh0SJUzV/BdZYjth94tG5toiMB1PPrYtxOCfaoUCkvtuH+3AJA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "xlsx": "bin/xlsx.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/xml-js": {
+ "version": "1.6.11",
+ "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
+ "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sax": "^1.2.4"
+ },
+ "bin": {
+ "xml-js": "bin/cli.js"
+ }
+ },
"node_modules/xml-parse-from-string": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz",
@@ -11983,15 +12810,15 @@
}
},
"node_modules/yaml": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",
- "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
+ "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
- "node": ">= 14"
+ "node": ">= 14.6"
}
},
"node_modules/yargs": {
diff --git a/package.json b/package.json
index 52860e1..32edb2d 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
},
"scripts": {
"dev": "vite",
+ "prebuild": "npm run i18n:pull",
"build": "tsc && vite build",
"serve": "vite preview",
"test": "vitest",
@@ -22,7 +23,9 @@
"script:create:tool": "node scripts/create-tool.mjs",
"lint": "eslint src --max-warnings=0 --fix",
"typecheck": "tsc --project tsconfig.json --noEmit",
- "prepare": "husky install"
+ "prepare": "husky install",
+ "i18n:pull": "locize download --project-id e7156a3e-66fb-4035-a0f0-cebf1c63a3ba --path ./public/locales",
+ "i18n:sync": "locize sync --project-id e7156a3e-66fb-4035-a0f0-cebf1c63a3ba --path ./public/locales --update-values true"
},
"dependencies": {
"@emotion/react": "^11.11.4",
@@ -41,6 +44,7 @@
"@types/lodash": "^4.17.5",
"@types/morsee": "^1.0.2",
"@types/omggif": "^1.0.5",
+ "@types/react-i18next": "^7.8.3",
"browser-image-compression": "^2.0.2",
"buffer": "^6.0.3",
"color": "^4.2.3",
@@ -49,10 +53,13 @@
"dayjs": "^1.11.13",
"fast-xml-parser": "^5.2.5",
"formik": "^2.4.6",
+ "i18next": "^25.3.2",
+ "i18next-http-backend": "^3.0.2",
"jimp": "^0.22.12",
"js-quantities": "^1.8.0",
"jszip": "^3.10.1",
"lint-staged": "^15.4.3",
+ "locize": "^4.0.14",
"lodash": "^4.17.21",
"mime": "^4.0.6",
"morsee": "^1.0.9",
@@ -68,6 +75,7 @@
"react-dom": "^18.3.1",
"react-filerobot-image-editor": "^4.9.1",
"react-helmet": "^6.1.0",
+ "react-i18next": "^15.6.0",
"react-image-crop": "^11.0.7",
"react-konva": "^18.2.10",
"react-router-dom": "^6.23.1",
@@ -102,6 +110,8 @@
"eslint-plugin-tailwindcss": "^3.17.0",
"happy-dom": "^12.10.3",
"husky": "^9.0.11",
+ "i18next-locize-backend": "^7.0.4",
+ "locize-cli": "^10.1.1",
"postcss": "^8.4.38",
"prettier": "3.1.1",
"start-server-and-test": "^2.0.4",
diff --git a/public/locales/de/audio.json b/public/locales/de/audio.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/audio.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/csv.json b/public/locales/de/csv.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/csv.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/image.json b/public/locales/de/image.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/image.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/json.json b/public/locales/de/json.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/json.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/list.json b/public/locales/de/list.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/list.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/number.json b/public/locales/de/number.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/number.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/pdf.json b/public/locales/de/pdf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/pdf.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/string.json b/public/locales/de/string.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/string.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/time.json b/public/locales/de/time.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/time.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/video.json b/public/locales/de/video.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/video.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/de/xml.json b/public/locales/de/xml.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/de/xml.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/en/audio.json b/public/locales/en/audio.json
new file mode 100644
index 0000000..8777e7e
--- /dev/null
+++ b/public/locales/en/audio.json
@@ -0,0 +1,42 @@
+{
+ "changeSpeed": {
+ "description": "Change the playback speed of audio files. Speed up or slow down audio while maintaining pitch.",
+ "inputTitle": "Input Audio",
+ "newAudioSpeed": "New Audio Speed",
+ "outputFormat": "Output Format",
+ "resultTitle": "Edited Audio",
+ "settingSpeed": "Setting Speed",
+ "shortDescription": "Change the speed of audio files",
+ "speedDescription": "Default multiplier: 2 means 2x faster",
+ "title": "Change audio speed",
+ "toolInfo": {
+ "title": "What is {{title}}?"
+ }
+ },
+ "extractAudio": {
+ "description": "Extract audio track from video files.",
+ "extractingAudio": "Extracting Audio",
+ "inputTitle": "Input Video",
+ "outputFormat": "Output Format",
+ "outputFormatDescription": "Select the format for the audio to be extracted as.",
+ "resultTitle": "Extracted Audio",
+ "shortDescription": "Extract audio from video files (MP4, MOV, etc.) to AAC, MP3, or WAV.",
+ "title": "Extract Audio from Video",
+ "toolInfo": {
+ "description": "This tool allows you to extract the audio track from video files. You can choose from different audio formats including AAC, MP3, and WAV.",
+ "title": "What is {{title}}?"
+ }
+ },
+ "mergeAudio": {
+ "description": "Combine multiple audio files into a single audio file by concatenating them in sequence.",
+ "longDescription": "This tool allows you to merge multiple audio files into a single file by concatenating them in the order you upload them. Perfect for combining podcast segments, music tracks, or any audio files that need to be joined together. Supports various audio formats including MP3, AAC, and WAV.",
+ "shortDescription": "Merge multiple audio files into one (MP3, AAC, WAV).",
+ "title": "Merge Audio"
+ },
+ "trim": {
+ "description": "Cut and trim audio files to extract specific segments by specifying start and end times.",
+ "longDescription": "This tool allows you to trim audio files by specifying start and end times. You can extract specific segments from longer audio files, remove unwanted parts, or create shorter clips. Supports various audio formats including MP3, AAC, and WAV. Perfect for podcast editing, music production, or any audio editing needs.",
+ "shortDescription": "Trim audio files to extract specific time segments (MP3, AAC, WAV).",
+ "title": "Trim Audio"
+ }
+}
diff --git a/public/locales/en/csv.json b/public/locales/en/csv.json
new file mode 100644
index 0000000..838322d
--- /dev/null
+++ b/public/locales/en/csv.json
@@ -0,0 +1,114 @@
+{
+ "changeCsvSeparator": {
+ "description": "Change the delimiter/separator in CSV files. Convert between different CSV formats like comma, semicolon, tab, or custom separators.",
+ "shortDescription": "Change CSV file delimiter",
+ "title": "Change CSV Separator"
+ },
+ "csvRowsToColumns": {
+ "description": "This tool converts rows of a CSV (Comma Separated Values) file into columns. It extracts the horizontal lines from the input CSV one by one, rotates them 90 degrees, and outputs them as vertical columns one after another, separated by commas.', longDescription: 'This tool converts rows of a CSV (Comma Separated Values) file into columns. For example, if the input CSV data has 6 rows, then the output will have 6 columns and the elements of the rows will be arranged from the top to bottom. In a well-formed CSV, the number of values in each row is the same. However, in cases when rows are missing fields, the program can fix them and you can choose from the available options: fill missing data with empty elements or replace missing data with custom elements, such as \"missing\", \"?\", or \"x\". During the conversion process, the tool also cleans the CSV file from unnecessary information, such as empty lines (these are lines without visible information) and comments. To help the tool correctly identify comments, in the options, you can specify the symbol at the beginning of a line that starts a comment. This symbol is typically a hash \"#\" or double slash \"//\". Csv-abulous!.",
+ "longDescription": "This tool converts rows of a CSV (Comma Separated Values) file into columns. For example, if the input CSV data has 6 rows, then the output will have 6 columns and the elements of the rows will be arranged from the top to bottom. In a well-formed CSV, the number of values in each row is the same. However, in cases when rows are missing fields, the program can fix them and you can choose from the available options: fill missing data with empty elements or replace missing data with custom elements, such as",
+ "shortDescription": "Convert CSV rows to columns.",
+ "title": "Convert CSV Rows to Columns"
+ },
+ "csvToJson": {
+ "columnSeparator": "Column Separator (e.g., , ; \\t)",
+ "commentSymbol": "Comment Symbol (e.g., #)",
+ "conversionOptions": "Conversion Options",
+ "description": "Convert CSV files to JSON format with customizable options for delimiters, quotes, and output formatting. Support for headers, comments, and dynamic type conversion.",
+ "dynamicTypes": "Dynamic Types",
+ "dynamicTypesDescription": "Automatically convert numbers and booleans",
+ "errorParsing": "Error parsing CSV: {{error}}",
+ "fieldQuote": "Field Quote (e.g., \")",
+ "inputCsvFormat": "Input CSV Format",
+ "inputTitle": "Input CSV",
+ "resultTitle": "Output JSON",
+ "shortDescription": "Convert CSV data to JSON format.",
+ "skipEmptyLines": "Skip Empty Lines",
+ "skipEmptyLinesDescription": "Ignore empty lines in the input CSV",
+ "title": "Convert CSV to JSON",
+ "useHeaders": "Use Headers",
+ "useHeadersDescription": "Treat the first row as column headers"
+ },
+ "csvToTsv": {
+ "description": "Upload your CSV file in the form below and it will automatically get converted to a TSV file. In the tool options, you can customize the input CSV format тАУ specify the field delimiter, quotation character, and comment symbol, as well as skip empty CSV lines, and choose whether to preserve CSV column headers.",
+ "longDescription": "This tool transforms Comma Separated Values (CSV) data to Tab Separated Values (TSV) data. Both CSV and TSV are popular file formats for storing tabular data but they use different delimiters to separate values тАУ CSV uses commas (",
+ "shortDescription": "Convert CSV data to TSV format.",
+ "title": "Convert CSV to TSV"
+ },
+ "csvToXml": {
+ "description": "Convert CSV files to XML format with customizable options.",
+ "shortDescription": "Convert CSV data to XML format.",
+ "title": "Convert CSV to XML"
+ },
+ "csvToYaml": {
+ "description": "Just upload your CSV file in the form below and it will automatically get converted to a YAML file. In the tool options, you can specify the field delimiter character, field quote character, and comment character to adapt the tool to custom CSV formats. Additionally, you can select the output YAML format: one that preserves CSV headers or one that excludes CSV headers.",
+ "longDescription": "This tool transforms CSV (Comma Separated Values) data into the YAML (Yet Another Markup Language) data. CSV is a simple, tabular format that is used to represent matrix-like data types consisting of rows and columns. YAML, on the other hand, is a more advanced format (actually a superset of JSON), which creates more human-readable data for serialization, and it supports lists, dictionaries, and nested objects. This program supports various input CSV formats тАУ the input data can be comma-separated (default), semicolon-separated, pipe-separated, or use another completely different delimiter. You can specify the exact delimiter your data uses in the options. Similarly, in the options, you can specify the quote character that is used to wrap CSV fields (by default a double-quote symbol). You can also skip lines that start with comments by specifying the comment symbols in the options. This allows you to keep your data clean by skipping unnecessary lines. There are two ways to convert CSV to YAML. The first method converts each CSV row into a YAML list. The second method extracts headers from the first CSV row and creates YAML objects with keys based on these headers. You can also customize the output YAML format by specifying the number of spaces for indenting YAML structures. If you need to perform the reverse conversion, that is, transform YAML into CSV, you can use our Convert YAML to CSV tool. Csv-abulous!",
+ "shortDescription": "Quickly convert a CSV file to a YAML file.",
+ "title": "Convert CSV to YAML"
+ },
+ "findIncompleteCsvRecords": {
+ "checkingOptions": "Checking Options",
+ "commentCharacterDescription": "Enter the character indicating the start of a comment line. Lines starting with this symbol will be skipped.",
+ "csvInputOptions": "CSV Input Options",
+ "csvSeparatorDescription": "Enter the character used to delimit columns in the CSV input file.",
+ "deleteLinesWithNoData": "Delete Lines with No Data",
+ "deleteLinesWithNoDataDescription": "Remove empty lines from CSV input file.",
+ "description": "Just upload your CSV file in the form below and this tool will automatically check if none of the rows or columns are missing values. In the tool options, you can adjust the input file format (specify the delimiter, quote character, and comment character). Additionally, you can enable checking for empty values, skip empty lines, and set a limit on the number of error messages in the output.",
+ "findEmptyValues": "Find Empty Values",
+ "findEmptyValuesDescription": "Display a message about CSV fields that are empty (These are not missing fields but fields that contain nothing).",
+ "inputTitle": "Input CSV",
+ "limitNumberOfMessages": "Limit number of messages",
+ "messageLimitDescription": "Set the limit of number of messages in the output.",
+ "quoteCharacterDescription": "Enter the quote character used to quote the CSV input fields.",
+ "resultTitle": "CSV Status",
+ "shortDescription": "Quickly find rows and columns in CSV that are missing values.",
+ "title": "Find incomplete CSV records",
+ "toolInfo": {
+ "title": "What is a {{title}}?"
+ }
+ },
+ "insertCsvColumns": {
+ "appendColumns": "Append columns",
+ "commentCharacterDescription": "Enter the character indicating the start of a comment line. Lines starting with this symbol will be skipped.",
+ "csvOptions": "CSV Options",
+ "csvSeparator": "CSV separator",
+ "csvToInsert": "CSV to insert",
+ "csvToInsertDescription": "Enter one or more columns you want to insert into the CSV. the character used to delimit columns has to be the same with the one in the CSV input file. Ps: Blank lines will be ignored",
+ "customFillDescription": "If the input CSV file is incomplete (missing values), then add empty fields or custom symbols to records to make a well-formed CSV?",
+ "customFillValueDescription": "Use this custom value to fill in missing fields. (Works only with \"Custom Values\" mode above.)",
+ "customPosition": "Custom position",
+ "customPositionOptionsDescription": "Select the method to insert the columns in the CSV file.",
+ "description": "Add new columns to CSV data at specified positions.",
+ "fillWithCustomValues": "Fill With Customs Values",
+ "fillWithEmptyValues": "Fill With Empty Values",
+ "headerName": "Header name",
+ "headerNameDescription": "Header of the column you want to insert columns after.",
+ "inputTitle": "Input CSV",
+ "insertingPositionDescription": "Specify where to insert the columns in the CSV file.",
+ "position": "Position",
+ "positionOptions": "Position Options",
+ "prependColumns": "Prepend columns",
+ "quoteCharDescription": "Enter the quote character used to quote the CSV input fields.",
+ "resultTitle": "Output CSV",
+ "rowNumberDescription": "Number of the column you want to insert columns after.",
+ "separatorDescription": "Enter the character used to delimit columns in the CSV input file.",
+ "shortDescription": "Quickly insert one or more new columns anywhere in a CSV file.",
+ "title": "Insert CSV columns",
+ "toolInfo": {
+ "description": "This tool allows you to insert new columns into CSV data at specified positions. You can prepend, append, or insert columns at custom positions based on header names or column numbers.",
+ "title": "Insert CSV Columns"
+ }
+ },
+ "swapCsvColumns": {
+ "description": "Just upload your CSV file in the form below, specify the columns to swap, and the tool will automatically change the positions of the specified columns in the output file. In the tool options, you can specify the column positions or names that you want to swap, as well as fix incomplete data and optionally remove empty records and records that have been commented out.",
+ "longDescription": "This tool reorganizes CSV data by swapping the positions of its columns. Swapping columns can enhance the readability of a CSV file by placing frequently used data together or in the front for easier data comparison and editing. For example, you can swap the first column with the last or swap the second column with the third. To swap columns based on their positions, select the",
+ "shortDescription": "Reorder CSV columns.",
+ "title": "Swap CSV Columns"
+ },
+ "transposeCsv": {
+ "description": "Just upload your CSV file in the form below, and this tool will automatically transpose your CSV. In the tool options, you can specify the character that starts the comment lines in the CSV to remove them. Additionally, if the CSV is incomplete (missing values), you can replace missing values with the empty character or a custom character.",
+ "longDescription": "This tool transposes Comma Separated Values (CSV). It treats the CSV as a matrix of data and flips all elements across the main diagonal. The output contains the same CSV data as the input, but now all the rows have become columns, and all the columns have become rows. After transposition, the CSV file will have opposite dimensions. For example, if the input file has 4 columns and 3 rows, the output file will have 3 columns and 4 rows. During conversion, the program also cleans the data from unnecessary lines and corrects incomplete data. Specifically, the tool automatically deletes all empty records and comments that begin with a specific character, which you can set in the option. Additionally, in cases where the CSV data is corrupted or lost, the utility completes the file with empty fields or custom fields that can be specified in the options. Csv-abulous!",
+ "shortDescription": "Quickly transpose a CSV file.",
+ "title": "Transpose CSV"
+ }
+}
diff --git a/public/locales/en/image.json b/public/locales/en/image.json
new file mode 100644
index 0000000..a7a66b3
--- /dev/null
+++ b/public/locales/en/image.json
@@ -0,0 +1,98 @@
+{
+ "changeColors": {
+ "description": "World",
+ "shortDescription": "Quickly swap colors in a image",
+ "title": "Change colors in image"
+ },
+ "changeOpacity": {
+ "description": "Easily adjust the transparency of your images. Simply upload your image, use the slider to set the desired opacity level between 0 (fully transparent) and 1 (fully opaque), and download the modified image.",
+ "shortDescription": "Adjust transparency of images",
+ "title": "Change image Opacity"
+ },
+ "compress": {
+ "description": "Reduce image file size while maintaining quality.",
+ "inputTitle": "Input image",
+ "resultTitle": "Compressed image",
+ "shortDescription": "Compress images to reduce file size while maintaining reasonable quality.",
+ "title": "Compress Image"
+ },
+ "compressPng": {
+ "description": "This is a program that compresses PNG pictures. As soon as you paste your PNG picture in the input area, the program will compress it and show the result in the output area. In the options, you can adjust the compression level, as well as find the old and new picture file sizes.",
+ "shortDescription": "Quickly compress a PNG",
+ "title": "Compress png"
+ },
+ "convertJgpToPng": {
+ "description": "Quickly convert your JPG images to PNG. Just import your PNG image in the editor on the left",
+ "shortDescription": "Quickly convert your JPG images to PNG",
+ "title": "Convert JPG to PNG"
+ },
+ "convertToJpg": {
+ "description": "Convert various image formats (PNG, GIF, TIF, PSD, SVG, WEBP, HEIC, RAW) to JPG with customizable quality and background color settings.",
+ "shortDescription": "Convert images to JPG with quality control",
+ "title": "Convert Images to JPG"
+ },
+ "createTransparent": {
+ "description": "World",
+ "shortDescription": "Quickly make an image transparent",
+ "title": "Create transparent PNG"
+ },
+ "crop": {
+ "description": "Crop images to remove unwanted areas.",
+ "inputTitle": "Input image",
+ "resultTitle": "Cropped image",
+ "shortDescription": "Crop images quickly.",
+ "title": "Crop Image"
+ },
+ "editor": {
+ "description": "Advanced image editor with tools for cropping, rotating, annotating, adjusting colors, and adding watermarks. Edit your images with professional-grade tools directly in your browser.",
+ "shortDescription": "Edit images with advanced tools and features",
+ "title": "Image Editor"
+ },
+ "imageToText": {
+ "description": "Extract text from images (JPG, PNG) using optical character recognition (OCR).",
+ "shortDescription": "Extract text from images using OCR.",
+ "title": "Image to Text (OCR)"
+ },
+ "qrCode": {
+ "description": "Generate QR codes for different data types: URL, Text, Email, Phone, SMS, WiFi, vCard, and more.",
+ "shortDescription": "Create customized QR codes for various data formats.",
+ "title": "QR Code Generator"
+ },
+ "removeBackground": {
+ "description": "World",
+ "shortDescription": "Automatically remove backgrounds from images",
+ "title": "Remove Background from Image"
+ },
+ "resize": {
+ "description": "Resize images to different dimensions.",
+ "dimensionType": "Dimension Type",
+ "heightDescription": "Height (in pixels)",
+ "inputTitle": "Input Image",
+ "maintainAspectRatio": "Maintain Aspect Ratio",
+ "maintainAspectRatioDescription": "Maintain the original aspect ratio of the image.",
+ "percentage": "Percentage",
+ "percentageDescription": "Percentage of original size (e.g., 50 for half size, 200 for double size)",
+ "resizeByPercentage": "Resize by Percentage",
+ "resizeByPercentageDescription": "Resize by specifying a percentage of the original size.",
+ "resizeByPixels": "Resize by Pixels",
+ "resizeByPixelsDescription": "Resize by specifying dimensions in pixels.",
+ "resizeMethod": "Resize Method",
+ "resultTitle": "Resized Image",
+ "setHeight": "Set Height",
+ "setHeightDescription": "Specify the height in pixels and calculate width based on aspect ratio.",
+ "setWidth": "Set Width",
+ "setWidthDescription": "Specify the width in pixels and calculate height based on aspect ratio.",
+ "shortDescription": "Resize images easily.",
+ "title": "Resize Image",
+ "toolInfo": {
+ "description": "This tool allows you to resize JPG, PNG, SVG, or GIF images. You can resize by specifying dimensions in pixels or by percentage, with options to maintain the original aspect ratio.",
+ "title": "Resize Image"
+ },
+ "widthDescription": "Width (in pixels)"
+ },
+ "rotate": {
+ "description": "Rotate an image by a specified angle.",
+ "shortDescription": "Rotate an image easily.",
+ "title": "Rotate Image"
+ }
+}
diff --git a/public/locales/en/json.json b/public/locales/en/json.json
new file mode 100644
index 0000000..634742f
--- /dev/null
+++ b/public/locales/en/json.json
@@ -0,0 +1,62 @@
+{
+ "escapeJson": {
+ "description": "Escape special characters in JSON strings. Convert JSON data to properly escaped format for safe transmission or storage.",
+ "shortDescription": "Escape special characters in JSON",
+ "title": "Escape JSON"
+ },
+ "jsonToXml": {
+ "description": "Convert JSON data to XML format. Transform structured JSON objects into well-formed XML documents.",
+ "shortDescription": "Convert JSON to XML format",
+ "title": "JSON to XML"
+ },
+ "minify": {
+ "description": "Remove all unnecessary whitespace from JSON.",
+ "inputTitle": "Input JSON",
+ "resultTitle": "Minified JSON",
+ "shortDescription": "Minify JSON by removing whitespace",
+ "title": "Minify JSON",
+ "toolInfo": {
+ "description": "JSON minification is the process of removing all unnecessary whitespace characters from JSON data while maintaining its validity. This includes removing spaces, newlines, and indentation that aren't required for the JSON to be parsed correctly. Minification reduces the size of JSON data, making it more efficient for storage and transmission while keeping the exact same data structure and values.",
+ "title": "What Is JSON Minification?"
+ }
+ },
+ "prettify": {
+ "description": "Format JSON with proper indentation and spacing.",
+ "indentation": "Indentation",
+ "inputTitle": "Input JSON",
+ "resultTitle": "Prettified JSON",
+ "shortDescription": "Format and beautify JSON code",
+ "title": "Prettify JSON",
+ "toolInfo": {
+ "description": "This tool allows you to format JSON data with proper indentation and spacing, making it more readable and easier to work with.",
+ "title": "Prettify JSON"
+ },
+ "useSpaces": "Use Spaces",
+ "useSpacesDescription": "Indent output with spaces",
+ "useTabs": "Use Tabs",
+ "useTabsDescription": "Indent output with tabs."
+ },
+ "stringify": {
+ "description": "Convert JavaScript objects to JSON string format. Serialize data structures into JSON strings for storage or transmission.",
+ "shortDescription": "Convert objects to JSON string",
+ "title": "Stringify JSON"
+ },
+ "tsvToJson": {
+ "description": "Convert TSV (Tab-Separated Values) data to JSON format. Transform tabular data into structured JSON objects.",
+ "shortDescription": "Convert TSV to JSON format",
+ "title": "TSV to JSON"
+ },
+ "validateJson": {
+ "description": "Check if JSON is valid and well-formed.",
+ "inputTitle": "Input JSON",
+ "invalidJson": "тЭМ {{error}}",
+ "resultTitle": "Validation Result",
+ "shortDescription": "Validate JSON code for errors",
+ "title": "Validate JSON",
+ "toolInfo": {
+ "description": "JSON (JavaScript Object Notation) is a lightweight data-interchange format. JSON validation ensures that the structure of the data conforms to the JSON standard. A valid JSON object must have: - Property names enclosed in double quotes. - Properly balanced curly braces {}. - No trailing commas after the last key-value pair. - Proper nesting of objects and arrays. This tool checks the input JSON and provides feedback to help identify and fix common errors.",
+ "title": "What is JSON Validation?"
+ },
+ "validJson": "тЬЕ Valid JSON"
+ }
+}
diff --git a/public/locales/en/list.json b/public/locales/en/list.json
new file mode 100644
index 0000000..c5131ba
--- /dev/null
+++ b/public/locales/en/list.json
@@ -0,0 +1,208 @@
+{
+ "duplicate": {
+ "concatenate": "Concatenate",
+ "concatenateDescription": "Concatenate copies (if unchecked, items will be interweaved)",
+ "copyDescription": "Number of copies (can be fractional)",
+ "description": "World's simplest browser-based utility for duplicating list items. Input your list and specify duplication criteria to create copies of items. Perfect for data expansion, testing, or creating repeated patterns.",
+ "duplicationOptions": "Duplication Options",
+ "examples": {
+ "fractional": {
+ "description": "This example shows how to duplicate a list with a fractional number of copies.",
+ "title": "Fractional duplication"
+ },
+ "interweave": {
+ "description": "This example shows how to interweave items instead of concatenating them.",
+ "title": "Interweaving items"
+ },
+ "reverse": {
+ "description": "This example shows how to duplicate a list in reverse order.",
+ "title": "Reverse duplication"
+ },
+ "simple": {
+ "description": "This example shows how to duplicate a list of words.",
+ "title": "Simple duplication"
+ }
+ },
+ "inputTitle": "Input List",
+ "joinSeparatorDescription": "Separator to join the duplicated list",
+ "resultTitle": "Duplicated List",
+ "reverse": "Reverse",
+ "reverseDescription": "Reverse the duplicated items",
+ "shortDescription": "Duplicate list items with specified criteria",
+ "splitByRegex": "Split by Regular Expression",
+ "splitBySymbol": "Split by Symbol",
+ "splitOptions": "Split Options",
+ "splitSeparatorDescription": "Separator to split the list",
+ "title": "Duplicate",
+ "toolInfo": {
+ "description": "This tool allows you to duplicate items in a list. You can specify the number of copies (including fractional values), control whether items are concatenated or interweaved, and even reverse the duplicated items. It's useful for creating repeated patterns, generating test data, or expanding lists with predictable content.",
+ "title": "List Duplication"
+ }
+ },
+ "findMostPopular": {
+ "description": "World's simplest browser-based utility for finding the most popular items in a list. Input your list and instantly get the items that appear most frequently. Perfect for data analysis, trend identification, or finding common elements.",
+ "shortDescription": "Find most frequently occurring items",
+ "title": "Find most popular"
+ },
+ "findUnique": {
+ "caseSensitiveItems": "Case Sensitive Items",
+ "caseSensitiveItemsDescription": "Output items with different case as unique elements in the list.",
+ "delimiterDescription": "Set a delimiting symbol or regular expression.",
+ "description": "World's simplest browser-based utility for finding unique items in a list. Input your list and instantly get all unique values with duplicates removed. Perfect for data cleaning, deduplication, or finding distinct elements.",
+ "findAbsolutelyUniqueItems": "Find Absolutely Unique Items",
+ "findAbsolutelyUniqueItemsDescription": "Display only those items of the list that exist in a single copy.",
+ "inputListDelimiter": "Input List Delimiter",
+ "inputTitle": "Input List",
+ "outputListDelimiter": "Output List Delimiter",
+ "resultTitle": "Unique Items",
+ "shortDescription": "Find unique items in a list",
+ "skipEmptyItems": "Skip Empty Items",
+ "skipEmptyItemsDescription": "Don't include the empty list items in the output.",
+ "title": "Find unique",
+ "trimItems": "Trim List Items",
+ "trimItemsDescription": "Remove leading and trailing spaces before comparing items.",
+ "uniqueItemOptions": "Unique Item Options"
+ },
+ "group": {
+ "deleteEmptyItems": "Delete Empty Items",
+ "deleteEmptyItemsDescription": "Ignore empty items and don't include them in the groups.",
+ "description": "World's simplest browser-based utility for grouping list items. Input your list and specify grouping criteria to organize items into logical groups. Perfect for categorizing data, organizing information, or creating structured lists. Supports custom separators and various grouping options.",
+ "emptyItemsAndPadding": "Empty Items and Padding",
+ "groupNumberDescription": "Number of items in a group",
+ "groupSeparatorDescription": "Group separator character",
+ "groupSizeAndSeparators": "Group Size and Separators",
+ "inputItemSeparator": "Input Item Separator",
+ "inputTitle": "Input list",
+ "itemSeparatorDescription": "Item separator character",
+ "leftWrapDescription": "Group's left wrap symbol.",
+ "padNonFullGroups": "Pad Non-full Groups",
+ "padNonFullGroupsDescription": "Fill non-full groups with a custom item (enter below).",
+ "paddingCharDescription": "Use this character or item to pad non-full groups.",
+ "resultTitle": "Grouped items",
+ "rightWrapDescription": "Group's right wrap symbol.",
+ "shortDescription": "Group list items by common properties",
+ "splitOperators": {
+ "regex": {
+ "description": "Delimit input list items with a regular expression.",
+ "title": "Use a Regex for Splitting"
+ },
+ "symbol": {
+ "description": "Delimit input list items with a character.",
+ "title": "Use a Symbol for Splitting"
+ }
+ },
+ "splitSeparatorDescription": "Set a delimiting symbol or regular expression.",
+ "title": "Group"
+ },
+ "reverse": {
+ "description": "This is a super simple browser-based application prints all list items in reverse. The input items can be separated by any symbol and you can also change the separator of the reversed list items.",
+ "inputTitle": "Input list",
+ "itemSeparator": "Item Separator",
+ "itemSeparatorDescription": "Set a delimiting symbol or regular expression.",
+ "outputListOptions": "Output List Options",
+ "outputSeparatorDescription": "Output list item separator.",
+ "resultTitle": "Reversed list",
+ "shortDescription": "Quickly reverse a list",
+ "splitOperators": {
+ "regex": {
+ "description": "Delimit input list items with a regular expression.",
+ "title": "Use a Regex for Splitting"
+ },
+ "symbol": {
+ "description": "Delimit input list items with a character.",
+ "title": "Use a Symbol for Splitting"
+ }
+ },
+ "splitterMode": "Splitter Mode",
+ "title": "Reverse",
+ "toolInfo": {
+ "description": "With this utility, you can reverse the order of items in a list. The utility first splits the input list into individual items and then iterates through them from the last item to the first item, printing each item to the output during the iteration. The input list may contain anything that can be represented as textual data, which includes digits, numbers, strings, words, sentences, etc. The input item separator can also be a regular expression. For example, the regex /[;,]/ will allow you to use items that are either comma- or semicolon-separated. The input and output list items delimiters can be customized in the options. By default, both input and output lists are comma-separated. Listabulous!",
+ "title": "What Is a List Reverser?"
+ }
+ },
+ "rotate": {
+ "description": "World's simplest browser-based utility for rotating list items. Input your list and specify rotation amount to shift items by a specified number of positions. Perfect for data manipulation, circular shifts, or reordering lists.",
+ "shortDescription": "Rotate list items by specified positions",
+ "title": "Rotate"
+ },
+ "shuffle": {
+ "delimiterDescription": "Set a delimiting symbol or regular expression.",
+ "description": "World's simplest browser-based utility for shuffling list items. Input your list and instantly get a randomized version with items in random order. Perfect for creating variety, testing randomness, or mixing up ordered data.",
+ "inputListSeparator": "Input list separator",
+ "inputTitle": "Input list",
+ "joinSeparatorDescription": "Use this separator in the randomized list.",
+ "outputLengthDescription": "Output this many random items",
+ "resultTitle": "Shuffled list",
+ "shortDescription": "Randomize the order of list items",
+ "shuffledListLength": "Shuffled List Length",
+ "shuffledListSeparator": "Shuffled List Separator",
+ "title": "Shuffle"
+ },
+ "sort": {
+ "caseSensitive": "Case Sensitive Sort",
+ "caseSensitiveDescription": "Sort uppercase and lowercase items separately. Capital letters precede lowercase letters in an ascending list. (Works only in alphabetical sorting mode.)",
+ "description": "World's simplest browser-based utility for sorting list items. Input your list and specify sorting criteria to organize items in ascending or descending order. Perfect for data organization, text processing, or creating ordered lists.",
+ "inputItemSeparator": "Input item separator",
+ "inputTitle": "Input list",
+ "joinSeparatorDescription": "Use this symbol as a joiner between items in a sorted list.",
+ "orderDescription": "Select a sorting order.",
+ "orderOptions": {
+ "decreasing": "Decreasing order",
+ "increasing": "Increasing order"
+ },
+ "removeDuplicates": "Remove duplicates",
+ "removeDuplicatesDescription": "Delete duplicate list items.",
+ "resultTitle": "Sorted list",
+ "shortDescription": "Sort list items in specified order",
+ "sortMethod": "Sort method",
+ "sortMethodDescription": "Select a sorting method.",
+ "sortOptions": {
+ "alphabetic": "Sort Alphabetically",
+ "length": "Sort by Length",
+ "numeric": "Sort Numerically"
+ },
+ "sortedItemProperties": "Sorted item properties",
+ "splitOperators": {
+ "regex": {
+ "description": "Delimit input list items with a regular expression.",
+ "title": "Use a Regex for Splitting"
+ },
+ "symbol": {
+ "description": "Delimit input list items with a character.",
+ "title": "Use a Symbol for Splitting"
+ }
+ },
+ "splitSeparatorDescription": "Set a delimiting symbol or regular expression.",
+ "title": "Sort"
+ },
+ "truncate": {
+ "description": "World's simplest browser-based utility for truncating lists. Input your list and specify the maximum number of items to keep. Perfect for data processing, list management, or limiting content length.",
+ "shortDescription": "Truncate list to specified number of items",
+ "title": "Truncate"
+ },
+ "unwrap": {
+ "description": "World's simplest browser-based utility for unwrapping list items. Input your wrapped list and specify unwrapping criteria to flatten organized items. Perfect for data processing, text manipulation, or extracting content from structured lists.",
+ "shortDescription": "Unwrap list items from structured format",
+ "title": "Unwrap"
+ },
+ "wrap": {
+ "description": "Add text before and after each list item.",
+ "inputTitle": "Input List",
+ "joinSeparatorDescription": "Separator to join the wrapped list",
+ "leftTextDescription": "Text to add before each item",
+ "removeEmptyItems": "Remove empty items",
+ "resultTitle": "Wrapped List",
+ "rightTextDescription": "Text to add after each item",
+ "shortDescription": "Wrap list items with specified criteria",
+ "splitByRegex": "Split by Regular Expression",
+ "splitBySymbol": "Split by Symbol",
+ "splitOptions": "Split Options",
+ "splitSeparatorDescription": "Separator to split the list",
+ "title": "Wrap",
+ "toolInfo": {
+ "description": "This tool allows you to add text before and after each item in a list. You can specify different text for the left and right sides, and control how the list is processed. It's useful for adding quotes, brackets, or other formatting to list items, preparing data for different formats, or creating structured text.",
+ "title": "List Wrapping"
+ },
+ "wrapOptions": "Wrap Options"
+ }
+}
diff --git a/public/locales/en/number.json b/public/locales/en/number.json
new file mode 100644
index 0000000..d2d1d45
--- /dev/null
+++ b/public/locales/en/number.json
@@ -0,0 +1,89 @@
+{
+ "arithmeticSequence": {
+ "commonDifferenceDescription": "Common difference between terms (d)",
+ "description": "Generate arithmetic sequences with customizable parameters.",
+ "firstTermDescription": "First term of the sequence (aтВБ)",
+ "numberOfTermsDescription": "Number of terms to generate (n)",
+ "outputFormat": "Output Format",
+ "resultTitle": "Generated Sequence",
+ "separatorDescription": "Separator between terms",
+ "sequenceParameters": "Sequence Parameters",
+ "shortDescription": "Generate arithmetic sequences",
+ "title": "Arithmetic Sequence",
+ "toolInfo": {
+ "description": "An arithmetic sequence is a sequence of numbers where the difference between each consecutive term is constant. This constant difference is called the common difference. Given the first term (aтВБ) and the common difference (d), each term can be found by adding the common difference to the previous term.",
+ "title": "What is an Arithmetic Sequence?"
+ }
+ },
+ "generate": {
+ "arithmeticSequenceOption": "Arithmetic sequence option",
+ "description": "Generate a sequence of numbers with customizable parameters.",
+ "numberOfElementsDescription": "Number of elements in sequence.",
+ "resultTitle": "Generated numbers",
+ "separator": "Separator",
+ "separatorDescription": "Separate elements in the arithmetic sequence by this character.",
+ "shortDescription": "Generate random numbers in specified ranges",
+ "startSequenceDescription": "Start sequence from this number.",
+ "stepDescription": "Increase each element by this amount",
+ "title": "Generate",
+ "toolInfo": {
+ "description": "This tool allows you to generate a sequence of numbers with customizable parameters. You can specify the starting value, step size, and number of elements.",
+ "title": "Generate numbers"
+ }
+ },
+ "ohmsLaw": {
+ "description": "Calculates voltage, current and resistance",
+ "longDescription": "This calculator applies Ohm's Law (V = I ├Ч R) to determine any of the three electrical parameters when the other two are known. Ohm's Law is a fundamental principle in electrical engineering that describes the relationship between voltage (V), current (I), and resistance (R). This tool is essential for electronics hobbyists, electrical engineers, and students working with circuits to quickly solve for unknown values in their electrical designs.",
+ "shortDescription": "Calculate voltage, current, or resistance in electrical circuits using Ohm's Law",
+ "title": "Ohm's Law"
+ },
+ "slackline": {
+ "description": "Calculates tension in a slackline",
+ "longDescription": "This calculator assumes a load in the center of the rope",
+ "shortDescription": "Calculate the approximate tension of a slackline or clothesline. Do not rely on this for safety.",
+ "title": "Slackline Tension"
+ },
+ "sphereArea": {
+ "description": "Area of a Sphere",
+ "longDescription": "This calculator determines the surface area of a sphere using the formula A = 4╧Аr┬▓. You can either input the radius to find the surface area or enter the surface area to calculate the required radius. This tool is useful for students studying geometry, engineers working with spherical objects, and anyone needing to perform calculations involving spherical surfaces.",
+ "shortDescription": "Calculate the surface area of a sphere based on its radius",
+ "title": "Area of a Sphere"
+ },
+ "sphereVolume": {
+ "description": "Volume of a Sphere",
+ "longDescription": "This calculator computes the volume of a sphere using the formula V = (4/3)╧Аr┬│. You can input either the radius or diameter to find the volume, or enter the volume to determine the required radius. The tool is valuable for students, engineers, and professionals working with spherical objects in fields such as physics, engineering, and manufacturing.",
+ "shortDescription": "Calculate the volume of a sphere using radius or diameter",
+ "title": "Volume of a Sphere"
+ },
+ "sum": {
+ "description": "Calculate the sum of a list of numbers. Enter numbers separated by commas or newlines to get their total sum.",
+ "extractionTypes": {
+ "delimiter": {
+ "description": "Customize the number separator here. (By default a line break.)",
+ "title": "Number Delimiter"
+ },
+ "smart": {
+ "description": "Auto detect numbers in the input.",
+ "title": "Smart Sum"
+ }
+ },
+ "inputTitle": "Input",
+ "numberExtraction": "Number Extraction",
+ "printRunningSum": "Print Running Sum",
+ "printRunningSumDescription": "Display the sum as it's calculated step by step.",
+ "resultTitle": "Total",
+ "runningSum": "Running Sum",
+ "shortDescription": "Calculate sum of numbers",
+ "title": "Sum",
+ "toolInfo": {
+ "description": "This is an online browser-based utility for calculating the sum of a bunch of numbers. You can enter the numbers separated by a comma, space, or any other character, including the line break. You can also simply paste a fragment of textual data that contains numerical values that you want to sum up and the utility will extract them and find their sum.",
+ "title": "What Is a Number Sum Calculator?"
+ }
+ },
+ "voltageDropInWire": {
+ "description": "Calculates round trip voltage and power loss in a 2 conductor cable",
+ "longDescription": "This calculator helps determine the voltage drop and power loss in a two-conductor electrical cable. It takes into account the cable length, wire gauge (cross-sectional area), material resistivity, and current flow. The tool calculates the round-trip voltage drop, total resistance of the cable, and the power dissipated as heat. This is particularly useful for electrical engineers, electricians, and hobbyists when designing electrical systems to ensure voltage levels remain within acceptable limits at the load.",
+ "shortDescription": "Calculate voltage drop and power loss in electrical cables based on length, material, and current",
+ "title": "Round trip voltage drop in cable"
+ }
+}
diff --git a/public/locales/en/pdf.json b/public/locales/en/pdf.json
new file mode 100644
index 0000000..eb4b98d
--- /dev/null
+++ b/public/locales/en/pdf.json
@@ -0,0 +1,113 @@
+{
+ "compressPdf": {
+ "compressedFileSize": "Compressed File Size",
+ "compressingPdf": "Compressing PDF...",
+ "compressionLevel": "Compression Level",
+ "compressionSettings": "Compression Settings",
+ "description": "Reduce PDF file size while maintaining quality using Ghostscript",
+ "errorCompressingPdf": "Failed to compress PDF: {{error}}",
+ "errorReadingPdf": "Failed to read PDF file. Please make sure it is a valid PDF.",
+ "fileSize": "Original File Size",
+ "highCompression": "High Compression",
+ "highCompressionDescription": "Maximum file size reduction with some quality loss",
+ "inputTitle": "Input PDF",
+ "lowCompression": "Low Compression",
+ "lowCompressionDescription": "Slightly reduce file size with minimal quality loss",
+ "mediumCompression": "Medium Compression",
+ "mediumCompressionDescription": "Balance between file size and quality",
+ "pages": "Number of Pages",
+ "resultTitle": "Compressed PDF",
+ "shortDescription": "Compress PDF files securely in your browser",
+ "title": "Compress PDF"
+ },
+ "editor": {
+ "description": "Advanced PDF editor with annotation, form-fill, highlight, and export capabilities. Edit your PDFs directly in the browser with professional-grade tools including text insertion, drawing, highlighting, signing and form filling.",
+ "shortDescription": "Edit PDFs with advanced annotation, signing and editing tools",
+ "title": "PDF Editor"
+ },
+ "merge": {
+ "inputTitle": "Input PDF",
+ "loadingText": "Extracting pages",
+ "resultTitle": "Output merged PDF",
+ "toolInfo": {
+ "description": "This tool allows you to merge multiple PDF files into a single document. To use the tool, simply upload the PDF files you want to merge. The tool will then combine all pages from the input files into a single PDF document.",
+ "title": "How to Use the Merge PDF Tool?"
+ }
+ },
+ "mergePdf": {
+ "description": "Combine multiple PDF files into a single document.",
+ "inputTitle": "Input PDFs",
+ "mergingPdfs": "Merging PDFs",
+ "pdfOptions": "PDF Options",
+ "resultTitle": "Merged PDF",
+ "shortDescription": "Merge multiple PDF files into a single document",
+ "sortByFileName": "Sort by file name",
+ "sortByFileNameDescription": "Sort PDFs alphabetically by file name",
+ "sortByUploadOrder": "Sort by upload order",
+ "sortByUploadOrderDescription": "Keep PDFs in the order they were uploaded",
+ "title": "Merge PDF",
+ "toolInfo": {
+ "description": "This tool allows you to combine multiple PDF files into a single document. You can choose how to sort the PDFs and the tool will merge them in the specified order.",
+ "title": "Merge PDF Files"
+ }
+ },
+ "pdfToEpub": {
+ "description": "Transform PDF documents into EPUB files for better e-reader compatibility.', icon: 'material-symbols:import-contacts', component: lazy(() => import('./index')), keywords: ['pdf', 'epub', 'convert', 'ebook'], path: 'pdf-to-epub', i18n: { name: 'pdf:pdfToEpub.title', description: 'pdf:pdfToEpub.description",
+ "shortDescription": "Convert PDF files to EPUB format",
+ "title": "PDF to EPUB"
+ },
+ "pdfToPng": {
+ "description": "Transform PDF documents into PNG panels.",
+ "longDescription": "Upload a PDF and convert each page into a high-quality PNG image directly in your browser. This tool is ideal for extracting visual content or sharing individual pages. No data is uploaded тАФ everything runs locally.",
+ "shortDescription": "Convert PDF into PNG images",
+ "title": "PDF to PNG"
+ },
+ "protectPdf": {
+ "description": "Add password protection to your PDF files securely in your browser",
+ "shortDescription": "Password protect PDF files securely",
+ "title": "Protect PDF"
+ },
+ "rotatePdf": {
+ "allPagesWillBeRotated": "All {{count}} pages will be rotated",
+ "angleOptions": {
+ "clockwise90": "90┬░ Clockwise",
+ "counterClockwise270": "270┬░ (90┬░ Counter-clockwise)",
+ "upsideDown180": "180┬░ (Upside down)"
+ },
+ "applyToAllPages": "Apply to all pages",
+ "description": "Rotate pages in a PDF document.",
+ "inputTitle": "Input PDF",
+ "longDescription": "Change the orientation of PDF pages by rotating them 90, 180, or 270 degrees. Useful for fixing incorrectly scanned documents or preparing PDFs for printing.",
+ "pageRangesDescription": "Enter page numbers or ranges separated by commas (e.g., 1,3,5-7)",
+ "pageRangesPlaceholder": "e.g., 1,5-8",
+ "pagesWillBeRotated": "{{count}} page{{count !== 1 ? 's' : ''}} will be rotated",
+ "pdfPageCount": "PDF has {{count}} page{{count !== 1 ? 's' : ''}}",
+ "resultTitle": "Rotated PDF",
+ "rotatingPages": "Rotating pages",
+ "rotationAngle": "Rotation Angle",
+ "rotationSettings": "Rotation Settings",
+ "shortDescription": "Rotate pages in a PDF document",
+ "title": "Rotate PDF",
+ "toolInfo": {
+ "description": "This tool allows you to rotate pages in a PDF document. You can rotate all pages or specify individual pages to rotate. Choose a rotation angle: 90┬░ Clockwise, 180┬░ (Upside down), or 270┬░ (90┬░ Counter-clockwise). To rotate specific pages, uncheck \"Apply to all pages\" and enter page numbers or ranges separated by commas (e.g., 1,3,5-7).",
+ "title": "How to Use the Rotate PDF Tool"
+ }
+ },
+ "splitPdf": {
+ "description": "Extract specific pages from a PDF document.",
+ "extractingPages": "Extracting pages",
+ "inputTitle": "Input PDF",
+ "pageExtractionPreview": "{{count}} page{{count !== 1 ? 's' : ''}} will be extracted",
+ "pageRangesDescription": "Enter page numbers or ranges separated by commas (e.g., 1,3,5-7)",
+ "pageRangesPlaceholder": "e.g., 1,5-8",
+ "pageSelection": "Page Selection",
+ "pdfPageCount": "PDF has {{count}} page{{count !== 1 ? 's' : ''}}",
+ "resultTitle": "Extracted PDF",
+ "shortDescription": "Extract specific pages from a PDF file",
+ "title": "Split PDF",
+ "toolInfo": {
+ "description": "This tool allows you to extract specific pages from a PDF document. You can specify individual pages or ranges of pages to extract.",
+ "title": "Split PDF"
+ }
+ }
+}
diff --git a/public/locales/en/string.json b/public/locales/en/string.json
new file mode 100644
index 0000000..6d1c342
--- /dev/null
+++ b/public/locales/en/string.json
@@ -0,0 +1,261 @@
+{
+ "base64": {
+ "decode": "Base64 Decode",
+ "description": "Encode or decode text using Base64 encoding.",
+ "encode": "Base64 Encode",
+ "inputTitle": "Input Data",
+ "optionsTitle": "Base64 Options",
+ "resultTitle": "Result",
+ "shortDescription": "Encode or decode data using Base64.",
+ "title": "Base64 Encoder/Decoder",
+ "toolInfo": {
+ "description": "Base64 is an encoding scheme that represents data in an ASCII string format by translating it into a radix-64 representation. Although it can be used to encode strings, it is commonly used to encode binary data for transmission over media that are designed to deal with textual data.",
+ "title": "What is Base64?"
+ }
+ },
+ "censor": {
+ "description": "utility for censoring words in text. Load your text in the input form on the left, specify all the bad words in the options, and you'll instantly get censored text in the output area.\", longDescription: 'With this online tool, you can censor certain words in any text. You can specify a list of unwanted words (such as swear words or secret words) and the program will replace them with alternative words and create a safe-to-read text. The words can be specified in a multi-line text field in the options by entering one word per line.', keywords: ['text', 'censor', 'words', 'characters'], component: lazy(() => import('./index')), i18n: { name: 'string:censor.title', description: 'string:censor.description",
+ "shortDescription": "Quickly mask bad words or replace them with alternative words.",
+ "title": "Text Censor"
+ },
+ "createPalindrome": {
+ "description": "World's simplest browser-based utility for creating palindromes from any text. Input text and instantly transform it into a palindrome that reads the same forward and backward. Perfect for word games, creating symmetrical text patterns, or exploring linguistic curiosities.",
+ "shortDescription": "Create text that reads the same forward and backward",
+ "title": "Create palindrome"
+ },
+ "extractSubstring": {
+ "description": "World's simplest browser-based utility for extracting substrings from text. Input your text and specify start and end positions to extract the desired portion. Perfect for data processing, text analysis, or extracting specific content from larger text blocks.",
+ "shortDescription": "Extract a portion of text between specified positions",
+ "title": "Extract substring"
+ },
+ "join": {
+ "blankLinesAndTrailingSpaces": "Blank Lines and Trailing Spaces",
+ "deleteBlankDescription": "Delete lines that don't have text symbols.",
+ "deleteBlankTitle": "Delete Blank Lines",
+ "deleteTrailingDescription": "Remove spaces and tabs at the end of the lines.",
+ "deleteTrailingTitle": "Delete Trailing Spaces",
+ "description": "Join text pieces together with customizable separators.",
+ "inputTitle": "Text Pieces",
+ "joinCharacterDescription": "Symbol that connects broken pieces of text. (Space by default.)",
+ "joinCharacterPlaceholder": "Join Character",
+ "resultTitle": "Joined Text",
+ "shortDescription": "Join text elements with a specified separator",
+ "textMergedOptions": "Text Merged Options",
+ "title": "Join Text",
+ "toolInfo": {
+ "description": "With this tool you can join parts of the text together. It takes a list of text values, separated by newlines, and merges them together. You can set the character that will be placed between the parts of the combined text. Also, you can ignore all empty lines and remove spaces and tabs at the end of all lines. Textabulous!",
+ "title": "What Is a Text Joiner?"
+ }
+ },
+ "palindrome": {
+ "description": "World's simplest browser-based utility for checking if text is a palindrome. Instantly verify if your text reads the same forward and backward. Perfect for word puzzles, linguistic analysis, or validating symmetrical text patterns. Supports various delimiters and multi-word palindrome detection.",
+ "shortDescription": "Check if text reads the same forward and backward",
+ "title": "Palindrome"
+ },
+ "passwordGenerator": {
+ "avoidAmbiguous": "Avoid ambiguous characters (i, I, l, 0, O)",
+ "description": "Generate secure random passwords with customizable length and character types. Choose from lowercase, uppercase, numbers, and special characters. Option to avoid ambiguous characters for better readability.",
+ "includeLowercase": "Include lowercase letters (a-z)",
+ "includeNumbers": "Include numbers (0-9)",
+ "includeSymbols": "Include special characters",
+ "includeUppercase": "Include uppercase letters (A-Z)",
+ "lengthDesc": "Length of the password",
+ "lengthPlaceholder": "e.g. 12",
+ "optionsTitle": "Password Options",
+ "resultTitle": "Generated Password",
+ "shortDescription": "Generate secure random passwords with custom options",
+ "title": "Password Generator",
+ "toolInfo": {
+ "description": "This tool generates secure random passwords based on your selected criteria. You can customize the length, include or exclude different character types, and avoid ambiguous characters for better readability. Perfect for creating strong passwords for accounts, applications, or any security needs.",
+ "title": "About Password Generator"
+ }
+ },
+ "quote": {
+ "allowDoubleQuotation": "Allow double quotation",
+ "description": "Add quotes around text with customizable options.",
+ "inputTitle": "Input Text",
+ "leftQuoteDescription": "Left quote character(s)",
+ "processAsMultiLine": "Process as multi-line text",
+ "quoteEmptyLines": "Quote empty lines",
+ "quoteOptions": "Quote Options",
+ "resultTitle": "Quoted Text",
+ "rightQuoteDescription": "Right quote character(s)",
+ "shortDescription": "Add quotes around text with various styles",
+ "title": "Text Quoter",
+ "toolInfo": {
+ "description": "This tool allows you to add quotes around text. You can choose different quote characters, handle multi-line text, and control how empty lines are processed. It's useful for preparing text for programming, formatting data, or creating stylized text.",
+ "title": "Text Quoter"
+ }
+ },
+ "randomizeCase": {
+ "description": "World's simplest browser-based utility for randomizing text case. Input your text and instantly transform it with random upper and lower case letters. Perfect for creating unique text effects, testing case sensitivity, or generating varied text patterns.",
+ "shortDescription": "Randomize the case of letters in text",
+ "title": "Randomize case"
+ },
+ "removeDuplicateLines": {
+ "description": "Load your text in the input form on the left and you'll instantly get text with no duplicate lines in the output area. Powerful, free, and fast. Load text lines тАУ get unique text lines",
+ "shortDescription": "Quickly delete all repeated lines from text",
+ "title": "Remove duplicate lines"
+ },
+ "repeat": {
+ "delimiterDescription": "Delimiter for output copies.",
+ "delimiterPlaceholder": "Delimiter",
+ "description": "Repeat text multiple times with customizable separators.",
+ "inputTitle": "Input text",
+ "numberPlaceholder": "Number",
+ "repeatAmountDescription": "Number of repetitions.",
+ "repetitionsDelimiter": "Repetitions Delimiter",
+ "resultTitle": "Repeated text",
+ "shortDescription": "Repeat text multiple times",
+ "textRepetitions": "Text Repetitions",
+ "title": "Repeat Text",
+ "toolInfo": {
+ "description": "This tool allows you to repeat a given text multiple times with an optional separator.",
+ "title": "Repeat text"
+ }
+ },
+ "reverse": {
+ "description": "World's simplest browser-based utility for reversing text. Input any text and get it instantly reversed, character by character. Perfect for creating mirror text, analyzing palindromes, or playing with text patterns. Preserves spaces and special characters while reversing.",
+ "inputTitle": "Text to reverse",
+ "processMultiLine": "Process multi-line text",
+ "processMultiLineDescription": "Each line will be reversed independently",
+ "resultTitle": "Reversed text",
+ "reversalOptions": "Reversal options",
+ "shortDescription": "Reverse any text character by character",
+ "skipEmptyLines": "Skip empty lines",
+ "skipEmptyLinesDescription": "Empty lines will be removed from the output",
+ "title": "Reverse",
+ "trimWhitespace": "Trim whitespace",
+ "trimWhitespaceDescription": "Remove leading and trailing whitespace from each line"
+ },
+ "rot13": {
+ "description": "Encode or decode text using ROT13 cipher.",
+ "inputTitle": "Input Text",
+ "resultTitle": "ROT13 Result",
+ "shortDescription": "Encode or decode text using ROT13 cipher.",
+ "title": "ROT13 Encoder/Decoder",
+ "toolInfo": {
+ "description": "ROT13 (rotate by 13 places) is a simple letter substitution cipher that replaces a letter with the 13th letter after it in the alphabet. ROT13 is a special case of the Caesar cipher which was developed in ancient Rome. Because there are 26 letters in the English alphabet, ROT13 is its own inverse; that is, to undo ROT13, the same algorithm is applied, so the same action can be used for encoding and decoding.",
+ "title": "What Is ROT13?"
+ }
+ },
+ "rotate": {
+ "description": "Rotate characters in text by specified positions.",
+ "inputTitle": "Input Text",
+ "processAsMultiLine": "Process as multi-line text (rotate each line separately)",
+ "resultTitle": "Rotated Text",
+ "rotateLeft": "Rotate Left",
+ "rotateRight": "Rotate Right",
+ "rotationOptions": "Rotation Options",
+ "shortDescription": "Shift characters in text by position.",
+ "stepDescription": "Number of positions to rotate",
+ "title": "Rotate Text",
+ "toolInfo": {
+ "description": "This tool allows you to rotate characters in a string by a specified number of positions. You can rotate to the left or right, and process multi-line text by rotating each line separately. String rotation is useful for simple text transformations, creating patterns, or implementing basic encryption techniques.",
+ "title": "String Rotation"
+ }
+ },
+ "split": {
+ "charAfterChunkDescription": "Character after each chunk",
+ "charBeforeChunkDescription": "Character before each chunk",
+ "chunksDescription": "Number of chunks of equal\nlength in the output.",
+ "chunksTitle": "Use a Number of Chunks",
+ "description": "World's simplest browser-based utility for splitting text. Input your text and specify a separator to split it into multiple parts. Perfect for data processing, text manipulation, or extracting specific content from larger text blocks.",
+ "lengthDescription": "Number of symbols that will be put in each output chunk.",
+ "lengthTitle": "Use Length for Splitting",
+ "outputSeparatorDescription": "Character that will be put between the split chunks.\n(It's newline \"\\n\" by default.)",
+ "outputSeparatorOptions": "Output separator options",
+ "regexDescription": "Regular expression that will be used to break text into parts.\n(Multiple spaces by default.)",
+ "regexTitle": "Use a Regex for Splitting",
+ "resultTitle": "Text pieces",
+ "shortDescription": "Split text into multiple parts using a separator",
+ "splitSeparatorOptions": "Split separator options",
+ "symbolDescription": "Character that will be used to break text into parts.\n(Space by default.)",
+ "symbolTitle": "Use a Symbol for Splitting",
+ "title": "Split"
+ },
+ "statistic": {
+ "characterFrequencyAnalysis": "Character Frequency Analysis",
+ "characterFrequencyAnalysisDescription": "Count how often each character appears in the text",
+ "delimitersOptions": "Delimiters Options",
+ "description": "Analyze text and generate comprehensive statistics.",
+ "includeEmptyLines": "Include Empty Lines",
+ "includeEmptyLinesDescription": "Include blank lines when counting lines",
+ "inputTitle": "Input text",
+ "resultTitle": "Text Statistics",
+ "sentenceDelimitersDescription": "Enter custom characters used to delimit sentences in your language (separated by comma) or leave it blank for default.",
+ "sentenceDelimitersPlaceholder": "e.g. ., !, ?, ...",
+ "shortDescription": "Get statistics about your text",
+ "statisticsOptions": "Statistics Options",
+ "title": "Text Statistics",
+ "toolInfo": {
+ "description": "This tool allows you to analyze text and generate comprehensive statistics including character count, word count, line count, and frequency analysis of characters and words.",
+ "title": "What is a {{title}}?"
+ },
+ "wordDelimitersDescription": "Enter custom Regex to count Words or leave it blank for default.",
+ "wordDelimitersPlaceholder": "eg. \\s.,;:!?\"┬л┬╗()тАж",
+ "wordFrequencyAnalysis": "Word Frequency Analysis",
+ "wordFrequencyAnalysisDescription": "Count how often each word appears in the text"
+ },
+ "textReplacer": {
+ "description": "Replace text patterns with new content.",
+ "findPatternInText": "Find This Pattern in Text",
+ "findPatternUsingRegexp": "Find a Pattern Using a RegExp",
+ "inputTitle": "Text to replace",
+ "newTextPlaceholder": "New text",
+ "regexpDescription": "Enter the regular expression that you want to replace.",
+ "replacePatternDescription": "Enter the pattern to use for replacement.",
+ "replaceText": "Replace Text",
+ "resultTitle": "Text with replacements",
+ "searchPatternDescription": "Enter the text pattern that you want to replace.",
+ "searchText": "Search text",
+ "shortDescription": "Quickly replace text in your content",
+ "title": "Text Replacer",
+ "toolInfo": {
+ "description": "Easily replace specific text in your content with this simple, browser-based tool. Just input your text, set the text you want to replace and the replacement value, and instantly get the updated version.",
+ "title": "Text Replacer"
+ }
+ },
+ "toMorse": {
+ "dashSymbolDescription": "Symbol that will correspond to the dash in Morse code.",
+ "description": "Convert text to Morse code.",
+ "dotSymbolDescription": "Symbol that will correspond to the dot in Morse code.",
+ "longSignal": "Long Signal",
+ "resultTitle": "Morse code",
+ "shortDescription": "Quickly encode text to morse",
+ "shortSignal": "Short Signal",
+ "title": "String To morse"
+ },
+ "truncate": {
+ "addTruncationIndicator": "Add Truncation Indicator",
+ "charactersPlaceholder": "Characters",
+ "description": "Shorten text to a specified length.",
+ "indicatorDescription": "Characters to add at the end (or start) of the text. Note: They count towards the length.",
+ "inputTitle": "Input text",
+ "leftSideDescription": "Remove characters from the start of the text.",
+ "leftSideTruncation": "Left-side Truncation",
+ "lengthAndLines": "Length and Lines",
+ "lineByLineDescription": "Truncate each line separately.",
+ "lineByLineTruncating": "Line-by-line Truncating",
+ "maxLengthDescription": "Number of characters to leave in the text.",
+ "numberPlaceholder": "Number",
+ "resultTitle": "Truncated text",
+ "rightSideDescription": "Remove characters from the end of the text.",
+ "rightSideTruncation": "Right-side Truncation",
+ "shortDescription": "Truncate text to a specified length",
+ "suffixAndAffix": "Suffix and Affix",
+ "title": "Truncate Text",
+ "toolInfo": {
+ "description": "Load your text in the input form on the left and you will automatically get truncated text on the right.",
+ "title": "Truncate text"
+ },
+ "truncationSide": "Truncation Side"
+ },
+ "uppercase": {
+ "description": "Convert text to uppercase letters.",
+ "inputTitle": "Input text",
+ "resultTitle": "Uppercase text",
+ "shortDescription": "Convert text to uppercase",
+ "title": "Convert to Uppercase"
+ }
+}
diff --git a/public/locales/en/time.json b/public/locales/en/time.json
new file mode 100644
index 0000000..4deda0b
--- /dev/null
+++ b/public/locales/en/time.json
@@ -0,0 +1,100 @@
+{
+ "checkLeapYears": {
+ "description": "Check if a year is a leap year and get leap year information.",
+ "inputTitle": "Input year",
+ "resultTitle": "Leap year result",
+ "shortDescription": "Check if a year is a leap year",
+ "title": "Check Leap Years",
+ "toolInfo": {
+ "description": "A leap year is a year containing one additional day (February 29) to keep the calendar year synchronized with the astronomical year. Leap years occur every 4 years, except for years that are divisible by 100 but not by 400.",
+ "title": "What is a Leap Year?"
+ }
+ },
+ "convertDaysToHours": {
+ "addHoursName": "Add Hours Name",
+ "addHoursNameDescription": "Append the string hours to output values",
+ "description": "Convert days to hours with customizable options.",
+ "hoursName": "Hours Name",
+ "shortDescription": "Convert days to hours",
+ "title": "Convert Days to Hours",
+ "toolInfo": {
+ "description": "This tool allows you to convert days to hours. You can input days as numbers or with units, and the tool will convert them to hours. You can also choose to append the 'hours' suffix to the output values.",
+ "title": "Convert Days to Hours"
+ }
+ },
+ "convertHoursToDays": {
+ "addDaysName": "Add Days Name",
+ "addDaysNameDescription": "Append the string days to output values",
+ "daysName": "Days Name",
+ "description": "Convert hours to days with customizable options.",
+ "shortDescription": "Convert hours to days",
+ "title": "Convert Hours to Days",
+ "toolInfo": {
+ "description": "This tool allows you to convert hours to days. You can input hours as numbers or with units, and the tool will convert them to days. You can also choose to append the 'days' suffix to the output values.",
+ "title": "Convert Hours to Days"
+ }
+ },
+ "convertSecondsToTime": {
+ "addPadding": "Add Padding",
+ "addPaddingDescription": "Add zero padding to hours, minutes, and seconds.",
+ "description": "Convert seconds to a readable time format (hours:minutes:seconds). Enter the number of seconds to get the formatted time.",
+ "shortDescription": "Convert seconds to time format",
+ "timePadding": "Time Padding",
+ "title": "Convert Seconds to Time",
+ "toolInfo": {
+ "title": "What is a {{title}}?"
+ }
+ },
+ "convertTimeToSeconds": {
+ "description": "Convert formatted time (HH:MM:SS) to seconds.",
+ "inputTitle": "Input time",
+ "resultTitle": "Seconds",
+ "shortDescription": "Convert time format to seconds",
+ "title": "Convert Time to Seconds",
+ "toolInfo": {
+ "description": "This tool allows you to convert formatted time strings (HH:MM:SS) to seconds. It's useful for calculating durations and time intervals.",
+ "title": "Convert Time to Seconds"
+ }
+ },
+ "crontabGuru": {
+ "description": "Generate and understand cron expressions. Create cron schedules for automated tasks and system jobs.",
+ "shortDescription": "Generate and understand cron expressions",
+ "title": "Crontab Guru"
+ },
+ "timeBetweenDates": {
+ "description": "Calculate the time difference between two dates. Get the exact duration in days, hours, minutes, and seconds.",
+ "endDate": "End Date",
+ "endDateTime": "End Date & Time",
+ "endTime": "End Time",
+ "endTimezone": "End Timezone",
+ "shortDescription": "Calculate time between two dates",
+ "startDate": "Start Date",
+ "startDateTime": "Start Date & Time",
+ "startTime": "Start Time",
+ "startTimezone": "Start Timezone",
+ "title": "Time Between Dates",
+ "toolInfo": {
+ "description": "Calculate the exact time difference between two dates and times, with support for different timezones. This tool provides a detailed breakdown of the time difference in various units (years, months, days, hours, minutes, and seconds).",
+ "title": "Time Between Dates Calculator"
+ }
+ },
+ "truncateClockTime": {
+ "description": "Truncate clock time to remove seconds or minutes. Round time to the nearest hour, minute, or custom interval.",
+ "printDroppedComponents": "Print Dropped Components",
+ "shortDescription": "Truncate clock time to specified precision",
+ "timePadding": "Time Padding",
+ "title": "Truncate Clock Time",
+ "toolInfo": {
+ "title": "What is a {{title}}?"
+ },
+ "truncateMinutesAndSeconds": "Truncate Minutes and Seconds",
+ "truncateMinutesAndSecondsDescription": "Drop both тАУ the minutes and seconds components from each clock time.",
+ "truncateOnlySeconds": "Truncate Only Seconds",
+ "truncateOnlySecondsDescription": "Drop the seconds component from each clock time.",
+ "truncationSide": "Truncation Side",
+ "useZeroPadding": "Use Zero Padding",
+ "zeroPaddingDescription": "Make all time components always be two digits wide.",
+ "zeroPrintDescription": "Display the dropped parts as zero values \"00\".",
+ "zeroPrintTruncatedParts": "Zero-print Truncated Parts"
+ }
+}
diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
new file mode 100644
index 0000000..e1832e1
--- /dev/null
+++ b/public/locales/en/translation.json
@@ -0,0 +1,254 @@
+{
+ "app": {
+ "language": "Language",
+ "title": "Omni Tools"
+ },
+ "audio": {
+ "changeSpeed": {
+ "description": "Change the playback speed of audio files. Speed up or slow down audio while maintaining pitch.",
+ "name": "Change audio speed",
+ "shortDescription": "Change the speed of audio files"
+ },
+ "extractAudio": {
+ "description": "Extract the audio track from a video file and save it as a separate audio file in your chosen format (AAC, MP3, WAV).",
+ "name": "Extract audio",
+ "shortDescription": "Extract audio from video files (MP4, MOV, etc.) to AAC, MP3, or WAV."
+ }
+ },
+ "baseFileInput": {
+ "copyFailed": "Failed to copy: {{error}}",
+ "dropFileHere": "Drop your {{type}} here",
+ "fileCopied": "File copied",
+ "selectFileDescription": "Click here to select a {{type}} from your device, press Ctrl+V to use a {{type}} from your clipboard, or drag and drop a file from desktop"
+ },
+ "categories": {
+ "audio": {
+ "description": "Tools for working with audio тАУ extract audio from video, adjusting audio speed, merging multiple audio files and much more.",
+ "title": "Audio Tools"
+ },
+ "csv": {
+ "description": "Tools for working with CSV files - convert CSV to different formats, manipulate CSV data, validate CSV structure, and process CSV files efficiently.",
+ "title": "CSV Tools"
+ },
+ "gif": {
+ "description": "Tools for working with GIF animations тАУ create transparent GIFs, extract GIF frames, add text to GIF, crop, rotate, reverse GIFs, and much more.",
+ "title": "GIF Tools"
+ },
+ "image-generic": {
+ "description": "Tools for working with pictures тАУ compress, resize, crop, convert to JPG, rotate, remove background and much more.",
+ "title": "Image Tools"
+ },
+ "json": {
+ "description": "Tools for working with JSON data structures тАУ prettify and minify JSON objects, flatten JSON arrays, stringify JSON values, analyze data, and much more",
+ "title": "JSON Tools"
+ },
+ "list": {
+ "description": "Tools for working with lists тАУ sort, reverse, randomize lists, find unique and duplicate list items, change list item separators, and much more.",
+ "title": "List Tools"
+ },
+ "number": {
+ "description": "Tools for working with numbers тАУ generate number sequences, convert numbers to words and words to numbers, sort, round, factor numbers, and much more.",
+ "title": "Number Tools"
+ },
+ "pdf": {
+ "description": "Tools for working with PDF files - extract text from PDFs, convert PDFs to other formats, manipulate PDFs, and much more.",
+ "title": "PDF Tools"
+ },
+ "png": {
+ "description": "Tools for working with PNG images тАУ convert PNGs to JPGs, create transparent PNGs, change PNG colors, crop, rotate, resize PNGs, and much more.",
+ "title": "PNG Tools"
+ },
+ "seeAll": "See all {{title}}",
+ "string": {
+ "description": "Tools for working with text тАУ convert text to images, find and replace text, split text into fragments, join text lines, repeat text, and much more.",
+ "title": "Text Tools"
+ },
+ "time": {
+ "description": "Tools for working with time and date тАУ calculate time differences, convert between time zones, format dates, generate date sequences, and much more.",
+ "title": "Time Tools"
+ },
+ "try": "Try {{title}}",
+ "video": {
+ "description": "Tools for working with videos тАУ extract frames from videos, create GIFs from videos, convert videos to different formats, and much more.",
+ "title": "Video Tools"
+ },
+ "xml": {
+ "description": "Tools for working with XML data structures - viewer, beautifier, validator and much more",
+ "title": "XML Tools"
+ }
+ },
+ "csv": {
+ "findIncompleteCsvRecords": {
+ "description": "Just upload your CSV file in the form below and this tool will automatically check if none of the rows or columns are missing values. In the tool options, you can adjust the input file format (specify the delimiter, quote character, and comment character). Additionally, you can enable checking for empty values, skip empty lines, and set a limit on the number of error messages in the output.",
+ "name": "Find incomplete CSV records",
+ "shortDescription": "Quickly find rows and columns in CSV that are missing values."
+ }
+ },
+ "hero": {
+ "brand": "OmniTools",
+ "description": "Boost your productivity with OmniTools, the ultimate toolkit for getting things done quickly! Access thousands of user-friendly utilities for editing images, text, lists, and data, all directly from your browser.",
+ "examples": {
+ "calculateNumberSum": "Calculate number sum",
+ "changeGifSpeed": "Change GIF speed",
+ "compressPng": "Compress PNG",
+ "createTransparentImage": "Create a transparent image",
+ "prettifyJson": "Prettify JSON",
+ "sortList": "Sort a list",
+ "splitPdf": "Split PDF",
+ "splitText": "Split a text",
+ "trimVideo": "Trim video"
+ },
+ "searchPlaceholder": "Search all tools",
+ "title": "Get Things Done Quickly with"
+ },
+ "inputFooter": {
+ "clear": "Clear",
+ "copyToClipboard": "Copy to clipboard",
+ "importFromFile": "Import from file"
+ },
+ "list": {
+ "group": {
+ "description": "World's simplest browser-based utility for grouping list items. Input your list and specify grouping criteria to organize items into logical groups. Perfect for categorizing data, organizing information, or creating structured lists. Supports custom separators and various grouping options.",
+ "name": "Group",
+ "shortDescription": "Group list items by common properties"
+ },
+ "reverse": {
+ "description": "This is a super simple browser-based application prints all list items in reverse. The input items can be separated by any symbol and you can also change the separator of the reversed list items.",
+ "name": "Reverse",
+ "shortDescription": "Quickly reverse a list"
+ },
+ "sort": {
+ "description": "This is a super simple browser-based application that sorts items in a list and arranges them in increasing or decreasing order. You can sort the items alphabetically, numerically, or by their length. You can also remove duplicate and empty items, as well as trim individual items that have whitespace around them. You can use any separator character to separate the input list items or alternatively use a regular expression to separate them. Additionally, you can create a new delimiter for the sorted output list.",
+ "name": "Sort",
+ "shortDescription": "Quickly sort a list"
+ }
+ },
+ "navbar": {
+ "buyMeACoffee": "Buy me a coffee",
+ "home": "Home",
+ "tools": "Tools"
+ },
+ "number": {
+ "generate": {
+ "description": "Quickly calculate a list of integers in your browser. To get your list, just specify the first integer, change value and total count in the options below, and this utility will generate that many integers",
+ "name": "Generate numbers",
+ "shortDescription": "Quickly calculate a list of integers in your browser"
+ },
+ "sum": {
+ "description": "This is a super simple browser-based application that sums numbers. The input numbers can be separated by any symbol and you can also change the separator of the summed numbers.",
+ "name": "Sum numbers",
+ "shortDescription": "Quickly sum a list of numbers"
+ }
+ },
+ "numericInputWithUnit": {
+ "unit": "Unit"
+ },
+ "pdf": {
+ "compressPdf": {
+ "description": "Reduce PDF file size while maintaining quality using Ghostscript",
+ "name": "Compress PDF",
+ "shortDescription": "Compress PDF files securely in your browser"
+ },
+ "mergePdf": {
+ "description": "Combine multiple PDF files into a single document.",
+ "name": "Merge PDF",
+ "shortDescription": "Merge multiple PDF files into a single document"
+ },
+ "pdfToEpub": {
+ "description": "Transform PDF documents into EPUB files for better e-reader compatibility.",
+ "name": "PDF to EPUB",
+ "shortDescription": "Convert PDF files to EPUB format"
+ },
+ "protectPdf": {
+ "description": "Add password protection to your PDF files securely in your browser",
+ "name": "Protect PDF",
+ "shortDescription": "Password protect PDF files securely"
+ },
+ "splitPdf": {
+ "description": "Extract specific pages from a PDF file using page numbers or ranges (e.g., 1,5-8)",
+ "name": "Split PDF",
+ "shortDescription": "Extract specific pages from a PDF file"
+ }
+ },
+ "resultFooter": {
+ "copy": "Copy to clipboard",
+ "download": "Download"
+ },
+ "string": {
+ "createPalindrome": {
+ "description": "World's simplest browser-based utility for creating palindromes from any text. Input text and instantly transform it into a palindrome that reads the same forward and backward. Perfect for word games, creating symmetrical text patterns, or exploring linguistic curiosities.",
+ "name": "Create palindrome",
+ "shortDescription": "Create text that reads the same forward and backward"
+ },
+ "palindrome": {
+ "description": "World's simplest browser-based utility for checking if text is a palindrome. Instantly verify if your text reads the same forward and backward. Perfect for word puzzles, linguistic analysis, or validating symmetrical text patterns. Supports various delimiters and multi-word palindrome detection.",
+ "name": "Palindrome",
+ "shortDescription": "Check if text reads the same forward and backward"
+ },
+ "repeat": {
+ "description": "This tool allows you to repeat a given text multiple times with an optional separator.",
+ "name": "Repeat text",
+ "shortDescription": "Repeat text multiple times"
+ },
+ "reverse": {
+ "description": "World's simplest browser-based utility for reversing text. Input any text and get it instantly reversed, character by character. Perfect for creating mirror text, analyzing palindromes, or playing with text patterns. Preserves spaces and special characters while reversing.",
+ "name": "Reverse",
+ "shortDescription": "Reverse any text character by character"
+ },
+ "toMorse": {
+ "description": "World's simplest browser-based utility for converting text to Morse code. Load your text in the input form on the left and you'll instantly get Morse code in the output area. Powerful, free, and fast. Load text тАУ get Morse code.",
+ "name": "String To morse",
+ "shortDescription": "Quickly encode text to morse"
+ },
+ "uppercase": {
+ "description": "World's simplest browser-based utility for converting text to uppercase. Just input your text and it will be automatically converted to all capital letters. Perfect for creating headlines, emphasizing text, or standardizing text format. Supports various text formats and preserves special characters.",
+ "name": "Uppercase",
+ "shortDescription": "Convert text to uppercase letters"
+ }
+ },
+ "toolExamples": {
+ "subtitle": "Click to try!",
+ "title": "{{title}} Examples"
+ },
+ "toolFileResult": {
+ "copied": "File copied",
+ "copyFailed": "Failed to copy: {{error}}",
+ "loading": "Loading... This may take a moment.",
+ "result": "Result"
+ },
+ "toolHeader": {
+ "seeExamples": "See Examples"
+ },
+ "toolLayout": {
+ "allToolsTitle": "All {{type}} Tools"
+ },
+ "toolMultiFileResult": {
+ "copied": "File copied",
+ "copyFailed": "Failed to copy: {{error}}",
+ "loading": "Loading... This may take a moment.",
+ "result": "Result"
+ },
+ "toolMultipleAudioInput": {
+ "inputTitle": "Input {{type}}",
+ "noFilesSelected": "No files selected"
+ },
+ "toolMultiplePdfInput": {
+ "inputTitle": "Input {{type}}",
+ "noFilesSelected": "No files selected"
+ },
+ "toolOptions": {
+ "title": "Tool options"
+ },
+ "toolTextInput": {
+ "copied": "Text copied",
+ "copyFailed": "Failed to copy: {{error}}",
+ "input": "Input text",
+ "placeholder": "Enter your text here..."
+ },
+ "toolTextResult": {
+ "copied": "Text copied",
+ "copyFailed": "Failed to copy: {{error}}",
+ "loading": "Loading... This may take a moment.",
+ "result": "Result"
+ }
+}
diff --git a/public/locales/en/video.json b/public/locales/en/video.json
new file mode 100644
index 0000000..d150ca8
--- /dev/null
+++ b/public/locales/en/video.json
@@ -0,0 +1,113 @@
+{
+ "changeSpeed": {
+ "defaultMultiplier": "Default multiplier: 2 means 2x faster",
+ "description": "Change the playback speed of video files. Speed up or slow down videos while maintaining audio synchronization. Supports various speed multipliers and common video formats.",
+ "inputTitle": "Input Video",
+ "newVideoSpeed": "New Video Speed",
+ "resultTitle": "Edited Video",
+ "settingSpeed": "Setting Speed",
+ "shortDescription": "Change video playback speed",
+ "title": "Change Video Speed",
+ "toolInfo": {
+ "title": "What is a {{title}}?"
+ }
+ },
+ "compress": {
+ "default": "Default",
+ "description": "Compress videos by scaling them to different resolutions like 240p, 480p, 720p, etc. This tool helps reduce file size while maintaining acceptable quality. Supports common video formats like MP4, WebM, and OGG.",
+ "inputTitle": "Input Video",
+ "loadingText": "Compressing video...",
+ "lossless": "Lossless",
+ "quality": "Quality (CRF)",
+ "resolution": "Resolution",
+ "resultTitle": "Compressed Video",
+ "shortDescription": "Compress videos by scaling to different resolutions",
+ "title": "Compress Video",
+ "worst": "Worst"
+ },
+ "cropVideo": {
+ "cropCoordinates": "Crop Coordinates",
+ "croppingVideo": "Cropping Video",
+ "description": "Crop video to remove unwanted areas.",
+ "errorBeyondHeight": "Crop area extends beyond video height ({{height}}px)",
+ "errorBeyondWidth": "Crop area extends beyond video width ({{width}}px)",
+ "errorCroppingVideo": "Error cropping video. Please check parameters and video file.",
+ "errorLoadingDimensions": "Failed to load video dimensions",
+ "errorNonNegativeCoordinates": "X and Y coordinates must be non-negative",
+ "errorPositiveDimensions": "Width and height must be positive",
+ "height": "Height",
+ "inputTitle": "Input Video",
+ "loadVideoForDimensions": "Load a video to see dimensions",
+ "resultTitle": "Cropped Video",
+ "shortDescription": "Crop video to remove unwanted areas",
+ "title": "Crop Video",
+ "toolInfo": {
+ "description": "This tool allows you to crop video files to remove unwanted areas. You can specify the crop area by setting the X, Y coordinates and width, height dimensions.",
+ "title": "Crop Video"
+ },
+ "videoDimensions": "Video dimensions: {{width}} ├Ч {{height}} pixels",
+ "videoInformation": "Video Information",
+ "width": "Width",
+ "xCoordinate": "X (left)",
+ "yCoordinate": "Y (top)"
+ },
+ "flip": {
+ "description": "Flip video files horizontally or vertically. Mirror videos for special effects or correct orientation issues.",
+ "flippingVideo": "Flipping Video",
+ "horizontalLabel": "Horizontal (Mirror)",
+ "inputTitle": "Input Video",
+ "orientation": "Orientation",
+ "resultTitle": "Flipped Video",
+ "shortDescription": "Flip video horizontally or vertically",
+ "title": "Flip Video",
+ "verticalLabel": "Vertical (Upside Down)"
+ },
+ "gif": {
+ "changeSpeed": {
+ "description": "Change the playback speed of GIF animations. Speed up or slow down GIFs while maintaining smooth animation.",
+ "shortDescription": "Change GIF animation speed",
+ "title": "Change GIF Speed"
+ }
+ },
+ "loop": {
+ "description": "Create a looping video by repeating the original video multiple times.",
+ "inputTitle": "Input Video",
+ "loopingVideo": "Looping Video",
+ "loops": "Loops",
+ "numberOfLoops": "Number of Loops",
+ "resultTitle": "Looped Video",
+ "shortDescription": "Create looping video files",
+ "title": "Loop Video",
+ "toolInfo": {
+ "description": "This tool allows you to create a looping video by repeating the original video multiple times. You can specify how many times the video should loop.",
+ "title": "What is a {{title}}?"
+ }
+ },
+ "rotate": {
+ "180Degrees": "180┬░ (Upside down)",
+ "270Degrees": "270┬░ (90┬░ Counter-clockwise)",
+ "90Degrees": "90┬░ Clockwise",
+ "description": "Rotate video files by 90, 180, or 270 degrees. Correct video orientation or create special effects with precise rotation control.",
+ "inputTitle": "Input Video",
+ "resultTitle": "Rotated Video",
+ "rotatingVideo": "Rotating Video",
+ "rotation": "Rotation",
+ "shortDescription": "Rotate video by specified degrees",
+ "title": "Rotate Video"
+ },
+ "trim": {
+ "description": "Trim video files by specifying start and end times. Remove unwanted sections from the beginning or end of videos.",
+ "endTime": "End Time",
+ "inputTitle": "Input Video",
+ "resultTitle": "Trimmed Video",
+ "shortDescription": "Trim video by removing unwanted sections",
+ "startTime": "Start Time",
+ "timestamps": "Timestamps",
+ "title": "Trim Video"
+ },
+ "videoToGif": {
+ "description": "Convert video files to animated GIF format. Extract specific time ranges and create shareable animated images.",
+ "shortDescription": "Convert video to animated GIF",
+ "title": "Video to GIF"
+ }
+}
diff --git a/public/locales/en/xml.json b/public/locales/en/xml.json
new file mode 100644
index 0000000..8acd4fc
--- /dev/null
+++ b/public/locales/en/xml.json
@@ -0,0 +1,38 @@
+{
+ "xmlBeautifier": {
+ "description": "Format XML with proper indentation and spacing.",
+ "indentation": "Indentation",
+ "inputTitle": "Input XML",
+ "resultTitle": "Beautified XML",
+ "shortDescription": "Format and beautify XML code",
+ "title": "XML Beautifier",
+ "toolInfo": {
+ "description": "This tool allows you to format XML data with proper indentation and spacing, making it more readable and easier to work with.",
+ "title": "XML Beautifier"
+ },
+ "useSpaces": "Use Spaces",
+ "useSpacesDescription": "Indent output with spaces",
+ "useTabs": "Use Tabs",
+ "useTabsDescription": "Indent output with tabs."
+ },
+ "xmlValidator": {
+ "description": "Validate XML syntax and structure.",
+ "placeholder": "Paste or import XML here...",
+ "shortDescription": "Validate XML code for errors",
+ "title": "XML Validator",
+ "toolInfo": {
+ "description": "This tool allows you to validate XML syntax and structure. It checks if the XML is well-formed and provides detailed error messages for any issues found.",
+ "title": "XML Validator"
+ }
+ },
+ "xmlViewer": {
+ "description": "View and explore XML structure in a tree format.",
+ "inputTitle": "Input XML",
+ "resultTitle": "XML Tree View",
+ "title": "XML Viewer",
+ "toolInfo": {
+ "description": "This tool allows you to view XML data in a hierarchical tree format, making it easier to explore and understand the structure of XML documents.",
+ "title": "XML Viewer"
+ }
+ }
+}
diff --git a/public/locales/es/audio.json b/public/locales/es/audio.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/audio.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/csv.json b/public/locales/es/csv.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/csv.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/image.json b/public/locales/es/image.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/image.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/json.json b/public/locales/es/json.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/json.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/list.json b/public/locales/es/list.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/list.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/number.json b/public/locales/es/number.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/number.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/pdf.json b/public/locales/es/pdf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/pdf.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/string.json b/public/locales/es/string.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/string.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/time.json b/public/locales/es/time.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/time.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/translation.json b/public/locales/es/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/video.json b/public/locales/es/video.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/video.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/es/xml.json b/public/locales/es/xml.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/es/xml.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/audio.json b/public/locales/fr/audio.json
new file mode 100644
index 0000000..ad77642
--- /dev/null
+++ b/public/locales/fr/audio.json
@@ -0,0 +1,5 @@
+{
+ "changeSpeed": {
+ "description": "Modifier la vitesse de lecture des fichiers audio. Acc├йl├йrer ou ralentir le son tout en conservant la hauteur."
+ }
+}
diff --git a/public/locales/fr/csv.json b/public/locales/fr/csv.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/csv.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/image.json b/public/locales/fr/image.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/image.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/json.json b/public/locales/fr/json.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/json.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/list.json b/public/locales/fr/list.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/list.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/number.json b/public/locales/fr/number.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/number.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/pdf.json b/public/locales/fr/pdf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/pdf.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/string.json b/public/locales/fr/string.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/string.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/time.json b/public/locales/fr/time.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/time.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/video.json b/public/locales/fr/video.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/video.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/fr/xml.json b/public/locales/fr/xml.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/fr/xml.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/hi/audio.json b/public/locales/hi/audio.json
new file mode 100644
index 0000000..4c6ce10
--- /dev/null
+++ b/public/locales/hi/audio.json
@@ -0,0 +1,64 @@
+{
+ "changeSpeed": {
+ "description": "рдСрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдкреНрд▓реЗрдмреИрдХ рдЧрддрд┐ рдмрджрд▓реЗрдВред",
+ "factorPlaceholder": "рдХрд╛рд░рдХ (рдЬреИрд╕реЗ 0.5, 1.5, 2.0)",
+ "formatAac": "AAC",
+ "formatMp3": "MP3",
+ "formatWav": "WAV",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдСрдбрд┐рдпреЛ",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "preservePitch": "рдкрд┐рдЪ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "resultTitle": "рдЧрддрд┐ рдмрджрд▓реА рдЧрдИ рдСрдбрд┐рдпреЛ",
+ "speedFactor": "рдЧрддрд┐ рдХрд╛рд░рдХ",
+ "speedOptions": "рдЧрддрд┐ рд╡рд┐рдХрд▓реНрдк",
+ "title": "рдСрдбрд┐рдпреЛ рдЧрддрд┐ рдмрджрд▓реЗрдВ"
+ },
+ "extractAudio": {
+ "audioFormat": "рдСрдбрд┐рдпреЛ рдкреНрд░рд╛рд░реВрдк",
+ "audioQuality": "рдСрдбрд┐рдпреЛ рдЧреБрдгрд╡рддреНрддрд╛",
+ "description": "рд╡реАрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдСрдбрд┐рдпреЛ рдЯреНрд░реИрдХ рдирд┐рдХрд╛рд▓реЗрдВред",
+ "extractAllTracks": "рд╕рднреА рдЯреНрд░реИрдХ рдирд┐рдХрд╛рд▓реЗрдВ",
+ "extractionOptions": "рдирд┐рдХрд╛рд▓рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "formatAac": "AAC",
+ "formatMp3": "MP3",
+ "formatWav": "WAV",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡реАрдбрд┐рдпреЛ",
+ "qualityHigh": "рдЙрдЪреНрдЪ",
+ "qualityLow": "рдХрдо",
+ "qualityMedium": "рдордзреНрдпрдо",
+ "resultTitle": "рдирд┐рдХрд╛рд▓рд╛ рдЧрдпрд╛ рдСрдбрд┐рдпреЛ",
+ "title": "рдСрдбрд┐рдпреЛ рдирд┐рдХрд╛рд▓реЗрдВ"
+ },
+ "mergeAudio": {
+ "description": "рдХрдИ рдСрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдПрдХ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред",
+ "formatAac": "AAC",
+ "formatMp3": "MP3",
+ "formatWav": "WAV",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдСрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓реЗрдВ",
+ "mergeMethod": "рдорд░реНрдЬ рд╡рд┐рдзрд┐",
+ "mergeOptions": "рдорд░реНрдЬ рд╡рд┐рдХрд▓реНрдк",
+ "methodConcat": "рдХреНрд░рдордмрджреНрдз рдЬреЛрдбрд╝рдирд╛",
+ "methodMix": "рдорд┐рд╢реНрд░рдг",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "resultTitle": "рдорд░реНрдЬ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдСрдбрд┐рдпреЛ",
+ "title": "рдСрдбрд┐рдпреЛ рдорд░реНрдЬ рдХрд░реЗрдВ"
+ },
+ "trim": {
+ "description": "рдСрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рднрд╛рдЧ рд╣рдЯрд╛рдПрдВред",
+ "endPlaceholder": "рд╕реЗрдХрдВрдб",
+ "endTime": "рдЕрдВрддрд┐рдо рд╕рдордп",
+ "fadeIn": "рдлреЗрдб рдЗрди",
+ "fadeInPlaceholder": "рд╕реЗрдХрдВрдб",
+ "fadeOut": "рдлреЗрдб рдЖрдЙрдЯ",
+ "fadeOutPlaceholder": "рд╕реЗрдХрдВрдб",
+ "formatMp3": "MP3",
+ "formatWav": "WAV",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдСрдбрд┐рдпреЛ",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "resultTitle": "рдЯреНрд░рд┐рдо рдХрд┐рдпрд╛ рдЧрдпрд╛ рдСрдбрд┐рдпреЛ",
+ "startPlaceholder": "рд╕реЗрдХрдВрдб",
+ "startTime": "рд╢реБрд░реБрдЖрддреА рд╕рдордп",
+ "title": "рдСрдбрд┐рдпреЛ рдЯреНрд░рд┐рдо рдХрд░реЗрдВ",
+ "trimOptions": "рдЯреНрд░рд┐рдо рд╡рд┐рдХрд▓реНрдк"
+ }
+}
diff --git a/public/locales/hi/csv.json b/public/locales/hi/csv.json
new file mode 100644
index 0000000..7843720
--- /dev/null
+++ b/public/locales/hi/csv.json
@@ -0,0 +1,123 @@
+{
+ "changeSeparator": {
+ "comma": "рдХреЙрдорд╛",
+ "commonSeparators": "рд╕рд╛рдорд╛рдиреНрдп рд╡рд┐рднрд╛рдЬрдХ",
+ "description": "CSV рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╡рд┐рднрд╛рдЬрдХ рд╡рд░реНрдг рдмрджрд▓реЗрдВред",
+ "inputSeparator": "рдЗрдирдкреБрдЯ рд╡рд┐рднрд╛рдЬрдХ",
+ "inputSeparatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "outputSeparator": "рдЖрдЙрдЯрдкреБрдЯ рд╡рд┐рднрд╛рдЬрдХ",
+ "outputSeparatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "pipe": "рдкрд╛рдЗрдк",
+ "resultTitle": "рдкрд░рд┐рд╡рд░реНрддрд┐рдд CSV",
+ "semicolon": "рд╕реЗрдореАрдХреЛрд▓рди",
+ "separatorOptions": "рд╡рд┐рднрд╛рдЬрдХ рд╡рд┐рдХрд▓реНрдк",
+ "tab": "рдЯреИрдм",
+ "title": "CSV рд╡рд┐рднрд╛рдЬрдХ рдмрджрд▓реЗрдВ"
+ },
+ "csvToJson": {
+ "arrayFormat": "рд╕рд░рдгреА рдкреНрд░рд╛рд░реВрдк",
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "CSV рдбреЗрдЯрд╛ рдХреЛ JSON рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "firstRowAsHeaders": "рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐ рд╢реАрд░реНрд╖рдХ рдХреЗ рд░реВрдк рдореЗрдВ",
+ "includeHeaders": "рд╢реАрд░реНрд╖рдХ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "objectFormat": "рдСрдмреНрдЬреЗрдХреНрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "resultTitle": "JSON рдкрд░рд┐рдгрд╛рдо",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "CSV рд╕реЗ JSON"
+ },
+ "csvToTsv": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "CSV рдлрд╝рд╛рдЗрд▓ рдХреЛ TSV рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "inputSeparator": "рдЗрдирдкреБрдЯ рд╡рд┐рднрд╛рдЬрдХ",
+ "inputSeparatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "preserveHeaders": "рд╢реАрд░реНрд╖рдХ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "resultTitle": "TSV рдкрд░рд┐рдгрд╛рдо",
+ "title": "CSV рд╕реЗ TSV"
+ },
+ "csvToXml": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "CSV рдбреЗрдЯрд╛ рдХреЛ XML рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "firstRowAsHeaders": "рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐ рд╢реАрд░реНрд╖рдХ рдХреЗ рд░реВрдк рдореЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "resultTitle": "XML рдкрд░рд┐рдгрд╛рдо",
+ "rootElement": "рдореВрд▓ рддрддреНрд╡",
+ "rootPlaceholder": "рддрддреНрд╡ рдирд╛рдо",
+ "rowElement": "рдкрдВрдХреНрддрд┐ рддрддреНрд╡",
+ "rowPlaceholder": "рддрддреНрд╡ рдирд╛рдо",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "CSV рд╕реЗ XML"
+ },
+ "csvToYaml": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "CSV рдбреЗрдЯрд╛ рдХреЛ YAML рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "firstRowAsHeaders": "рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐ рд╢реАрд░реНрд╖рдХ рдХреЗ рд░реВрдк рдореЗрдВ",
+ "includeHeaders": "рд╢реАрд░реНрд╖рдХ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "indentSize": "рдЗрдВрдбреЗрдВрдЯ рдЖрдХрд╛рд░",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "resultTitle": "YAML рдкрд░рд┐рдгрд╛рдо",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "sizePlaceholder": "рдЖрдХрд╛рд░",
+ "title": "CSV рд╕реЗ YAML"
+ },
+ "findIncompleteRecords": {
+ "checkEmptyValues": "рдЦрд╛рд▓реА рдореВрд▓реНрдп рдЬрд╛рдВрдЪреЗрдВ",
+ "description": "CSV рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЕрдзреВрд░реЗ рд░рд┐рдХреЙрд░реНрдб рдЦреЛрдЬреЗрдВред",
+ "errorLimit": "рддреНрд░реБрдЯрд┐ рд╕реАрдорд╛",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "limitPlaceholder": "рд╕реАрдорд╛",
+ "resultTitle": "рдЕрдзреВрд░реЗ рд░рд┐рдХреЙрд░реНрдб",
+ "searchOptions": "рдЦреЛрдЬ рд╡рд┐рдХрд▓реНрдк",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "skipEmptyLines": "рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпрд╛рдВ рдЫреЛрдбрд╝реЗрдВ",
+ "title": "рдЕрдзреВрд░реЗ CSV рд░рд┐рдХреЙрд░реНрдб рдЦреЛрдЬреЗрдВ"
+ },
+ "insertColumns": {
+ "columnNames": "рд╕реНрддрдВрдн рдирд╛рдо",
+ "defaultValues": "рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдореВрд▓реНрдп",
+ "description": "CSV рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдирдП рд╕реНрддрдВрдн рдбрд╛рд▓реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "insertPosition": "рдбрд╛рд▓рдиреЗ рдХреА рд╕реНрдерд┐рддрд┐",
+ "insertionOptions": "рдбрд╛рд▓рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "namesPlaceholder": "рдирд╛рдо (рдХреЙрдорд╛ рд╕реЗ рдЕрд▓рдЧ)",
+ "positionPlaceholder": "рд╕реНрдерд┐рддрд┐",
+ "resultTitle": "рд╕рдВрд╢реЛрдзрд┐рдд CSV",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "CSV рд╕реНрддрдВрдн рдбрд╛рд▓реЗрдВ",
+ "valuesPlaceholder": "рдореВрд▓реНрдп (рдХреЙрдорд╛ рд╕реЗ рдЕрд▓рдЧ)"
+ },
+ "rowsToColumns": {
+ "description": "CSV рдбреЗрдЯрд╛ рдХреЛ рдкрдВрдХреНрддрд┐рдпреЛрдВ рд╕реЗ рд╕реНрддрдВрднреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "includeHeaders": "рд╢реАрд░реНрд╖рдХ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "resultTitle": "рдкрд░рд┐рд╡рд░реНрддрд┐рдд CSV",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "CSV рдкрдВрдХреНрддрд┐рдпрд╛рдВ рд╕реЗ рд╕реНрддрдВрдн",
+ "transformationOptions": "рдкрд░рд┐рд╡рд░реНрддрди рд╡рд┐рдХрд▓реНрдк",
+ "transposeData": "рдбреЗрдЯрд╛ рдЯреНрд░рд╛рдВрд╕рдкреЛрдЬрд╝ рдХрд░реЗрдВ"
+ },
+ "swapColumns": {
+ "description": "CSV рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реНрддрдВрднреЛрдВ рдХреА рд╕реНрдерд┐рддрд┐ рдмрджрд▓реЗрдВред",
+ "firstColumn": "рдкрд╣рд▓рд╛ рд╕реНрддрдВрдн",
+ "firstColumnPlaceholder": "рд╕реНрддрдВрдн рд╕рдВрдЦреНрдпрд╛",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "resultTitle": "рд╕рдВрд╢реЛрдзрд┐рдд CSV",
+ "secondColumn": "рджреВрд╕рд░рд╛ рд╕реНрддрдВрдн",
+ "secondColumnPlaceholder": "рд╕реНрддрдВрдн рд╕рдВрдЦреНрдпрд╛",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "swapOptions": "рдмрджрд▓рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "title": "CSV рд╕реНрддрдВрдн рдмрджрд▓реЗрдВ"
+ },
+ "transposeCsv": {
+ "description": "CSV рдбреЗрдЯрд╛ рдХреЛ рдЯреНрд░рд╛рдВрд╕рдкреЛрдЬрд╝ рдХрд░реЗрдВ (рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд╕реНрддрдВрднреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВ)ред",
+ "includeHeaders": "рд╢реАрд░реНрд╖рдХ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ CSV",
+ "resultTitle": "рдЯреНрд░рд╛рдВрд╕рдкреЛрдЬрд╝ рдХрд┐рдпрд╛ рдЧрдпрд╛ CSV",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "CSV рдЯреНрд░рд╛рдВрд╕рдкреЛрдЬрд╝ рдХрд░реЗрдВ",
+ "transposeOptions": "рдЯреНрд░рд╛рдВрд╕рдкреЛрдЬрд╝ рд╡рд┐рдХрд▓реНрдк"
+ }
+}
diff --git a/public/locales/hi/image.json b/public/locales/hi/image.json
new file mode 100644
index 0000000..4fd86c6
--- /dev/null
+++ b/public/locales/hi/image.json
@@ -0,0 +1,152 @@
+{
+ "compress": {
+ "compressionOptions": "рд╕рдВрдкреАрдбрд╝рди рд╡рд┐рдХрд▓реНрдк",
+ "description": "рдЫрд╡рд┐ рдлрд╝рд╛рдЗрд▓ рдЖрдХрд╛рд░ рдХрдо рдХрд░реЗрдВред",
+ "formatJpeg": "JPEG",
+ "formatPng": "PNG",
+ "formatWebp": "WebP",
+ "imageQuality": "рдЫрд╡рд┐ рдЧреБрдгрд╡рддреНрддрд╛",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЫрд╡рд┐",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "progressiveJpeg": "рдкреНрд░рдЧрддрд┐рд╢реАрд▓ JPEG",
+ "qualityPlaceholder": "рдЧреБрдгрд╡рддреНрддрд╛ (1-100)",
+ "removeMetadata": "рдореЗрдЯрд╛рдбреЗрдЯрд╛ рд╣рдЯрд╛рдПрдВ",
+ "resultTitle": "рд╕рдВрдкреАрдбрд╝рд┐рдд рдЫрд╡рд┐",
+ "title": "рдЫрд╡рд┐ рд╕рдВрдкреАрдбрд╝рд┐рдд рдХрд░реЗрдВ"
+ },
+ "convert": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "рдЫрд╡рд┐ рдХреЛ рдПрдХ рдкреНрд░рд╛рд░реВрдк рд╕реЗ рджреВрд╕рд░реЗ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "formatBmp": "BMP",
+ "formatGif": "GIF",
+ "formatJpeg": "JPEG",
+ "formatPng": "PNG",
+ "formatTiff": "TIFF",
+ "formatWebp": "WebP",
+ "imageQuality": "рдЫрд╡рд┐ рдЧреБрдгрд╡рддреНрддрд╛",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЫрд╡рд┐",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "preserveTransparency": "рдкрд╛рд░рджрд░реНрд╢рд┐рддрд╛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "qualityPlaceholder": "рдЧреБрдгрд╡рддреНрддрд╛ (1-100)",
+ "resultTitle": "рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдЫрд╡рд┐",
+ "title": "рдЫрд╡рд┐ рдкреНрд░рд╛рд░реВрдк рдмрджрд▓реЗрдВ"
+ },
+ "crop": {
+ "aspectRatio": "рдЖрдХрд╛рд░ рдЕрдиреБрдкрд╛рдд",
+ "cropArea": "рдХреНрд░реЙрдк рдХреНрд╖реЗрддреНрд░",
+ "cropMethod": "рдХреНрд░реЙрдк рд╡рд┐рдзрд┐",
+ "cropOptions": "рдХреНрд░реЙрдк рд╡рд┐рдХрд▓реНрдк",
+ "description": "рдЫрд╡рд┐ рд╕реЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рднрд╛рдЧ рд╣рдЯрд╛рдПрдВред",
+ "height": "рдКрдВрдЪрд╛рдИ",
+ "heightPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЫрд╡рд┐",
+ "methodAspectRatio": "рдЖрдХрд╛рд░ рдЕрдиреБрдкрд╛рдд",
+ "methodManual": "рдореИрдиреБрдЕрд▓",
+ "ratio16x9": "16:9",
+ "ratio1x1": "1:1",
+ "ratio3x2": "3:2",
+ "ratio4x3": "4:3",
+ "resultTitle": "рдХреНрд░реЙрдк рдХреА рдЧрдИ рдЫрд╡рд┐",
+ "title": "рдЫрд╡рд┐ рдХреНрд░реЙрдк рдХрд░реЗрдВ",
+ "width": "рдЪреМрдбрд╝рд╛рдИ",
+ "widthPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "xPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "xPosition": "X рд╕реНрдерд┐рддрд┐",
+ "yPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "yPosition": "Y рд╕реНрдерд┐рддрд┐"
+ },
+ "filter": {
+ "description": "рдЫрд╡рд┐ рдкрд░ рд╡рд┐рднрд┐рдиреНрди рдлрд╝рд┐рд▓реНрдЯрд░ рд▓рд╛рдЧреВ рдХрд░реЗрдВред",
+ "filterIntensity": "рдлрд╝рд┐рд▓реНрдЯрд░ рддреАрд╡реНрд░рддрд╛",
+ "filterOptions": "рдлрд╝рд┐рд▓реНрдЯрд░ рд╡рд┐рдХрд▓реНрдк",
+ "filterType": "рдлрд╝рд┐рд▓реНрдЯрд░ рдкреНрд░рдХрд╛рд░",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЫрд╡рд┐",
+ "intensityPlaceholder": "рдорд╛рди (0-100)",
+ "resultTitle": "рдлрд╝рд┐рд▓реНрдЯрд░ рдХреА рдЧрдИ рдЫрд╡рд┐",
+ "title": "рдЫрд╡рд┐ рдлрд╝рд┐рд▓реНрдЯрд░",
+ "typeBlur": "рдзреБрдВрдзрд▓рд╛",
+ "typeBrightness": "рдЪрдордХ",
+ "typeContrast": "рдХрдВрдЯреНрд░рд╛рд╕реНрдЯ",
+ "typeGrayscale": "рдЧреНрд░реЗрд╕реНрдХреЗрд▓",
+ "typeInvert": "рдЙрд▓рдЯрд╛",
+ "typeSaturation": "рд╕рдВрддреГрдкреНрддрд┐",
+ "typeSepia": "рд╕реЗрдкрд┐рдпрд╛",
+ "typeSharpen": "рддреЗрдЬрд╝"
+ },
+ "flip": {
+ "description": "рдЫрд╡рд┐ рдХреЛ рдХреНрд╖реИрддрд┐рдЬ рдпрд╛ рд▓рдВрдмрд╡рдд рд░реВрдк рд╕реЗ рдлреНрд▓рд┐рдк рдХрд░реЗрдВред",
+ "directionBoth": "рджреЛрдиреЛрдВ",
+ "directionHorizontal": "рдХреНрд╖реИрддрд┐рдЬ",
+ "directionVertical": "рд▓рдВрдмрд╡рдд",
+ "flipDirection": "рдлреНрд▓рд┐рдк рджрд┐рд╢рд╛",
+ "flipOptions": "рдлреНрд▓рд┐рдк рд╡рд┐рдХрд▓реНрдк",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЫрд╡рд┐",
+ "resultTitle": "рдлреНрд▓рд┐рдк рдХреА рдЧрдИ рдЫрд╡рд┐",
+ "title": "рдЫрд╡рд┐ рдлреНрд▓рд┐рдк рдХрд░реЗрдВ"
+ },
+ "resize": {
+ "description": "рдЫрд╡рд┐ рдХрд╛ рдЖрдХрд╛рд░ рдмрджрд▓реЗрдВред",
+ "height": "рдКрдВрдЪрд╛рдИ",
+ "heightPlaceholder": "рдорд╛рди",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЫрд╡рд┐",
+ "interpolationMethod": "рдЗрдВрдЯрд░рдкреЛрд▓реЗрд╢рди рд╡рд┐рдзрд┐",
+ "maintainAspectRatio": "рдЖрдХрд╛рд░ рдЕрдиреБрдкрд╛рдд рдмрдирд╛рдП рд░рдЦреЗрдВ",
+ "methodAspectRatio": "рдЖрдХрд╛рд░ рдЕрдиреБрдкрд╛рдд",
+ "methodBicubic": "рджреНрд╡рд┐рдШрди",
+ "methodBilinear": "рджреНрд╡рд┐рд░реЗрдЦреАрдп",
+ "methodNearest": "рдирд┐рдХрдЯрддрдо",
+ "methodPercentage": "рдкреНрд░рддрд┐рд╢рдд",
+ "methodPixels": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "resizeMethod": "рдЖрдХрд╛рд░ рдмрджрд▓рдиреЗ рдХреА рд╡рд┐рдзрд┐",
+ "resizeOptions": "рдЖрдХрд╛рд░ рдмрджрд▓рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "resultTitle": "рдЖрдХрд╛рд░ рдмрджрд▓реА рдЧрдИ рдЫрд╡рд┐",
+ "title": "рдЫрд╡рд┐ рдЖрдХрд╛рд░ рдмрджрд▓реЗрдВ",
+ "width": "рдЪреМрдбрд╝рд╛рдИ",
+ "widthPlaceholder": "рдорд╛рди"
+ },
+ "rotate": {
+ "angle180": "180 рдбрд┐рдЧреНрд░реА",
+ "angle270": "270 рдбрд┐рдЧреНрд░реА",
+ "angle90": "90 рдбрд┐рдЧреНрд░реА",
+ "backgroundColor": "рдкреГрд╖реНрдарднреВрдорд┐ рд░рдВрдЧ",
+ "colorBlack": "рдХрд╛рд▓рд╛",
+ "colorCustom": "рдХрд╕реНрдЯрдо",
+ "colorTransparent": "рдкрд╛рд░рджрд░реНрд╢реА",
+ "colorWhite": "рд╕рдлреЗрдж",
+ "customAngle": "рдХрд╕реНрдЯрдо рдХреЛрдг",
+ "customAnglePlaceholder": "рдбрд┐рдЧреНрд░реА",
+ "customColorPlaceholder": "#RRGGBB",
+ "description": "рдЫрд╡рд┐ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреЛрдг рд╕реЗ рдШреБрдорд╛рдПрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЫрд╡рд┐",
+ "resultTitle": "рдШреБрдорд╛рдИ рдЧрдИ рдЫрд╡рд┐",
+ "rotationAngle": "рдШреБрдорд╛рдиреЗ рдХрд╛ рдХреЛрдг",
+ "rotationOptions": "рдШреБрдорд╛рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "title": "рдЫрд╡рд┐ рдШреБрдорд╛рдПрдВ"
+ },
+ "watermark": {
+ "colorPlaceholder": "#RRGGBB",
+ "description": "рдЫрд╡рд┐ рдкрд░ рдЯреЗрдХреНрд╕реНрдЯ рдпрд╛ рдЫрд╡рд┐ рд╡реЙрдЯрд░рдорд╛рд░реНрдХ рдЬреЛрдбрд╝реЗрдВред",
+ "fontColor": "рдлрд╝реЙрдиреНрдЯ рд░рдВрдЧ",
+ "fontSize": "рдлрд╝реЙрдиреНрдЯ рдЖрдХрд╛рд░",
+ "fontSizePlaceholder": "рдЖрдХрд╛рд░",
+ "imagePlaceholder": "рдЫрд╡рд┐ рдлрд╝рд╛рдЗрд▓",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЫрд╡рд┐",
+ "opacity": "рдкрд╛рд░рджрд░реНрд╢рд┐рддрд╛",
+ "opacityPlaceholder": "рдкреНрд░рддрд┐рд╢рдд (1-100)",
+ "position": "рд╕реНрдерд┐рддрд┐",
+ "positionBottomLeft": "рдиреАрдЪреЗ рдмрд╛рдПрдВ",
+ "positionBottomRight": "рдиреАрдЪреЗ рджрд╛рдПрдВ",
+ "positionCenter": "рдХреЗрдВрджреНрд░",
+ "positionTopLeft": "рдКрдкрд░ рдмрд╛рдПрдВ",
+ "positionTopRight": "рдКрдкрд░ рджрд╛рдПрдВ",
+ "resultTitle": "рд╡реЙрдЯрд░рдорд╛рд░реНрдХ рд╡рд╛рд▓реА рдЫрд╡рд┐",
+ "textPlaceholder": "рдЯреЗрдХреНрд╕реНрдЯ",
+ "title": "рдЫрд╡рд┐ рдкрд░ рд╡реЙрдЯрд░рдорд╛рд░реНрдХ",
+ "typeImage": "рдЫрд╡рд┐",
+ "typeText": "рдЯреЗрдХреНрд╕реНрдЯ",
+ "watermarkImage": "рд╡реЙрдЯрд░рдорд╛рд░реНрдХ рдЫрд╡рд┐",
+ "watermarkOptions": "рд╡реЙрдЯрд░рдорд╛рд░реНрдХ рд╡рд┐рдХрд▓реНрдк",
+ "watermarkText": "рд╡реЙрдЯрд░рдорд╛рд░реНрдХ рдЯреЗрдХреНрд╕реНрдЯ",
+ "watermarkType": "рд╡реЙрдЯрд░рдорд╛рд░реНрдХ рдкреНрд░рдХрд╛рд░"
+ }
+}
diff --git a/public/locales/hi/json.json b/public/locales/hi/json.json
new file mode 100644
index 0000000..448d41c
--- /dev/null
+++ b/public/locales/hi/json.json
@@ -0,0 +1,80 @@
+{
+ "escape": {
+ "description": "JSON рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рд╡рд┐рд╢реЗрд╖ рд╡рд░реНрдгреЛрдВ рдХреЛ рдПрд╕реНрдХреЗрдк рдХрд░реЗрдВред",
+ "escapeBackslashes": "рдмреИрдХрд╕реНрд▓реИрд╢ рдПрд╕реНрдХреЗрдк рдХрд░реЗрдВ",
+ "escapeNewlines": "рдирдИ рдкрдВрдХреНрддрд┐рдпрд╛рдВ рдПрд╕реНрдХреЗрдк рдХрд░реЗрдВ",
+ "escapeOptions": "рдПрд╕реНрдХреЗрдк рд╡рд┐рдХрд▓реНрдк",
+ "escapeQuotes": "рдЙрджреНрдзрд░рдг рдПрд╕реНрдХреЗрдк рдХрд░реЗрдВ",
+ "escapeTabs": "рдЯреИрдм рдПрд╕реНрдХреЗрдк рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ JSON",
+ "resultTitle": "рдПрд╕реНрдХреЗрдк рдХрд┐рдпрд╛ рдЧрдпрд╛ JSON",
+ "title": "JSON рдПрд╕реНрдХреЗрдк рдХрд░реЗрдВ"
+ },
+ "jsonToXml": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "JSON рдбреЗрдЯрд╛ рдХреЛ XML рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "includeAttributes": "рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "indentSize": "рдЗрдВрдбреЗрдВрдЯ рдЖрдХрд╛рд░",
+ "inputTitle": "рдЗрдирдкреБрдЯ JSON",
+ "resultTitle": "XML рдкрд░рд┐рдгрд╛рдо",
+ "rootElement": "рдореВрд▓ рддрддреНрд╡",
+ "rootPlaceholder": "рддрддреНрд╡ рдирд╛рдо",
+ "sizePlaceholder": "рдЖрдХрд╛рд░",
+ "title": "JSON рд╕реЗ XML"
+ },
+ "minify": {
+ "compactArrays": "рд╕рд░рдгрд┐рдпрд╛рдВ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдХрд░реЗрдВ",
+ "description": "JSON рдХреЛ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ JSON",
+ "minifyOptions": "рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "removeComments": "рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдВ рд╣рдЯрд╛рдПрдВ",
+ "removeWhitespace": "рд╕рдлреЗрдж рд╕реНрдерд╛рди рд╣рдЯрд╛рдПрдВ",
+ "resultTitle": "рд╕рдВрдХреНрд╖рд┐рдкреНрдд JSON",
+ "title": "JSON рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдХрд░реЗрдВ"
+ },
+ "prettify": {
+ "description": "JSON рдХреЛ рд╕реБрдВрджрд░ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "formattingOptions": "рдлреЙрд░реНрдореЗрдЯрд┐рдВрдЧ рд╡рд┐рдХрд▓реНрдк",
+ "indentCharacter": "рдЗрдВрдбреЗрдВрдЯ рд╡рд░реНрдг",
+ "indentSize": "рдЗрдВрдбреЗрдВрдЯ рдЖрдХрд╛рд░",
+ "inputTitle": "рдЗрдирдкреБрдЯ JSON",
+ "resultTitle": "рд╕реБрдВрджрд░ JSON",
+ "sizePlaceholder": "рдЖрдХрд╛рд░",
+ "sortKeys": "рдХреБрдВрдЬрд┐рдпрд╛рдВ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ",
+ "space": "рд╕реНрдкреЗрд╕",
+ "tab": "рдЯреИрдм",
+ "title": "JSON рд╕реБрдВрджрд░ рдмрдирд╛рдПрдВ"
+ },
+ "stringify": {
+ "description": "JavaScript рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ JSON рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "includeFunctions": "рдлрд╝рдВрдХреНрд╢рди рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "includeUndefined": "рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдСрдмреНрдЬреЗрдХреНрдЯ",
+ "prettyPrint": "рд╕реБрдВрджрд░ рдкреНрд░рд┐рдВрдЯ",
+ "resultTitle": "JSON рд╕реНрдЯреНрд░рд┐рдВрдЧ",
+ "stringifyOptions": "рд╕реНрдЯреНрд░рд┐рдВрдЧрд┐рдлрд╛рдИ рд╡рд┐рдХрд▓реНрдк",
+ "title": "JSON рд╕реНрдЯреНрд░рд┐рдВрдЧрд┐рдлрд╛рдИ"
+ },
+ "tsvToJson": {
+ "arrayFormat": "рд╕рд░рдгреА рдкреНрд░рд╛рд░реВрдк",
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "TSV рдбреЗрдЯрд╛ рдХреЛ JSON рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "firstRowAsHeaders": "рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐ рд╢реАрд░реНрд╖рдХ рдХреЗ рд░реВрдк рдореЗрдВ",
+ "includeHeaders": "рд╢реАрд░реНрд╖рдХ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ TSV",
+ "objectFormat": "рдСрдмреНрдЬреЗрдХреНрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "resultTitle": "JSON рдкрд░рд┐рдгрд╛рдо",
+ "title": "TSV рд╕реЗ JSON"
+ },
+ "validateJson": {
+ "allowComments": "рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдВ рдЕрдиреБрдорддрд┐ рджреЗрдВ",
+ "allowTrailingCommas": "рдЕрдиреБрдЧрд╛рдореА рдХреЙрдорд╛ рдЕрдиреБрдорддрд┐ рджреЗрдВ",
+ "description": "JSON рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреА рд╡реИрдзрддрд╛ рдЬрд╛рдВрдЪреЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ JSON",
+ "resultTitle": "рдорд╛рдиреНрдпрддрд╛ рдкрд░рд┐рдгрд╛рдо",
+ "strictMode": "рд╕рдЦреНрдд рдореЛрдб",
+ "title": "JSON рдорд╛рдиреНрдп рдХрд░реЗрдВ",
+ "validationOptions": "рдорд╛рдиреНрдпрддрд╛ рд╡рд┐рдХрд▓реНрдк"
+ }
+}
diff --git a/public/locales/hi/list.json b/public/locales/hi/list.json
new file mode 100644
index 0000000..e0efbac
--- /dev/null
+++ b/public/locales/hi/list.json
@@ -0,0 +1,138 @@
+{
+ "duplicate": {
+ "countPlaceholder": "рд╕рдВрдЦреНрдпрд╛",
+ "description": "рд╕реВрдЪреА рдореЗрдВ рдЖрдЗрдЯрдо рдХреЛ рджреЛрд╣рд░рд╛рдПрдВред",
+ "duplicateAll": "рд╕рднреА рдЖрдЗрдЯрдо рджреЛрд╣рд░рд╛рдПрдВ",
+ "duplicateCount": "рджреЛрд╣рд░рд╛рд╡ рдХреА рд╕рдВрдЦреНрдпрд╛",
+ "duplicateEach": "рдкреНрд░рддреНрдпреЗрдХ рдЖрдЗрдЯрдо рджреЛрд╣рд░рд╛рдПрдВ",
+ "duplicationOptions": "рджреЛрд╣рд░рд╛рд╡ рд╡рд┐рдХрд▓реНрдк",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "resultTitle": "рджреЛрд╣рд░рд╛рдИ рдЧрдИ рд╕реВрдЪреА",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "рдЖрдЗрдЯрдо рджреЛрд╣рд░рд╛рдПрдВ"
+ },
+ "findMostPopular": {
+ "caseSensitive": "рдХреЗрд╕ рд╕рдВрд╡реЗрджреА",
+ "countPlaceholder": "рд╕рдВрдЦреНрдпрд╛",
+ "description": "рд╕реВрдЪреА рдореЗрдВ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рдмрд╛рд░ рдЖрдиреЗ рд╡рд╛рд▓реЗ рдЖрдЗрдЯрдо рдЦреЛрдЬреЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "popularityOptions": "рд▓реЛрдХрдкреНрд░рд┐рдпрддрд╛ рд╡рд┐рдХрд▓реНрдк",
+ "removeEmpty": "рдЦрд╛рд▓реА рдЖрдЗрдЯрдо рд╣рдЯрд╛рдПрдВ",
+ "resultTitle": "рд▓реЛрдХрдкреНрд░рд┐рдп рдЖрдЗрдЯрдо",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "рд╕рдмрд╕реЗ рд▓реЛрдХрдкреНрд░рд┐рдп рдЦреЛрдЬреЗрдВ",
+ "topCount": "рд╢реАрд░реНрд╖ рд╕рдВрдЦреНрдпрд╛"
+ },
+ "findUnique": {
+ "caseSensitive": "рдХреЗрд╕ рд╕рдВрд╡реЗрджреА",
+ "description": "рд╕реВрдЪреА рд╕реЗ рдЕрджреНрд╡рд┐рддреАрдп рдЖрдЗрдЯрдо рдирд┐рдХрд╛рд▓реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "removeEmpty": "рдЦрд╛рд▓реА рдЖрдЗрдЯрдо рд╣рдЯрд╛рдПрдВ",
+ "resultTitle": "рдЕрджреНрд╡рд┐рддреАрдп рдЖрдЗрдЯрдо",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "рдЕрджреНрд╡рд┐рддреАрдп рдЖрдЗрдЯрдо рдЦреЛрдЬреЗрдВ",
+ "trimWhitespace": "рд╕рдлреЗрдж рд╕реНрдерд╛рди рдЯреНрд░рд┐рдо рдХрд░реЗрдВ",
+ "uniqueOptions": "рдЕрджреНрд╡рд┐рддреАрдп рд╡рд┐рдХрд▓реНрдк"
+ },
+ "group": {
+ "description": "рд╕реВрдЪреА рдЖрдЗрдЯрдо рдХреЛ рд╕рдореВрд╣рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд░рд▓ рдЙрдкрдХрд░рдгред",
+ "groupByFirstChar": "рдкрд╣рд▓реЗ рд╡рд░реНрдг рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╕рдореВрд╣рд┐рдд рдХрд░реЗрдВ",
+ "groupByLastChar": "рдЕрдВрддрд┐рдо рд╡рд░реНрдг рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╕рдореВрд╣рд┐рдд рдХрд░реЗрдВ",
+ "groupByLength": "рд▓рдВрдмрд╛рдИ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╕рдореВрд╣рд┐рдд рдХрд░реЗрдВ",
+ "groupByPattern": "рдкреИрдЯрд░реНрди рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╕рдореВрд╣рд┐рдд рдХрд░реЗрдВ",
+ "groupHeaders": "рд╕рдореВрд╣ рд╢реАрд░реНрд╖рдХ рдЬреЛрдбрд╝реЗрдВ",
+ "groupingOptions": "рд╕рдореВрд╣реАрдХрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "patternPlaceholder": "рд░реЗрдЧреЗрдХреНрд╕ рдкреИрдЯрд░реНрди",
+ "resultTitle": "рд╕рдореВрд╣рд┐рдд рд╕реВрдЪреА",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "рд╕реВрдЪреА рд╕рдореВрд╣рд┐рдд рдХрд░реЗрдВ"
+ },
+ "reverse": {
+ "description": "рд╕реВрдЪреА рдореЗрдВ рдЖрдЗрдЯрдо рдХреЗ рдХреНрд░рдо рдХреЛ рдЙрд▓рдЯрд╛ рдХрд░реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "resultTitle": "рдЙрд▓рдЯреА рд╕реВрдЪреА",
+ "reverseEachItem": "рдкреНрд░рддреНрдпреЗрдХ рдЖрдЗрдЯрдо рдЙрд▓рдЯрд╛ рдХрд░реЗрдВ",
+ "reverseOptions": "рдЙрд▓рдЯрд╛рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "reverseOrder": "рдХреНрд░рдо рдЙрд▓рдЯрд╛ рдХрд░реЗрдВ",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "рд╕реВрдЪреА рдЙрд▓рдЯрд╛ рдХрд░реЗрдВ"
+ },
+ "rotate": {
+ "description": "рд╕реВрдЪреА рдореЗрдВ рдЖрдЗрдЯрдо рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реНрдерд╛рдиреЛрдВ рджреНрд╡рд╛рд░рд╛ рдШреБрдорд╛рдПрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "resultTitle": "рдШреБрдорд╛рдИ рдЧрдИ рд╕реВрдЪреА",
+ "rotateDirection": "рдШреБрдорд╛рдиреЗ рдХреА рджрд┐рд╢рд╛",
+ "rotateLeft": "рдмрд╛рдИрдВ рдУрд░ рдШреБрдорд╛рдПрдВ",
+ "rotateRight": "рджрд╛рдИрдВ рдУрд░ рдШреБрдорд╛рдПрдВ",
+ "rotateSteps": "рдШреБрдорд╛рдиреЗ рдХреЗ рдЪрд░рдг",
+ "rotationOptions": "рдШреБрдорд╛рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "stepsPlaceholder": "рдЪрд░рдгреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛",
+ "title": "рд╕реВрдЪреА рдШреБрдорд╛рдПрдВ"
+ },
+ "shuffle": {
+ "description": "рд╕реВрдЪреА рдореЗрдВ рдЖрдЗрдЯрдо рдХреЛ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдХреНрд░рдо рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "randomSeed": "рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдмреАрдЬ",
+ "resultTitle": "рдлреЗрд░рдмрджрд▓ рдХреА рдЧрдИ рд╕реВрдЪреА",
+ "seedPlaceholder": "рдмреАрдЬ рдорд╛рди",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "shuffleOptions": "рдлреЗрд░рдмрджрд▓ рд╡рд┐рдХрд▓реНрдк",
+ "title": "рд╕реВрдЪреА рдлреЗрд░рдмрджрд▓ рдХрд░реЗрдВ"
+ },
+ "sort": {
+ "ascending": "рдЖрд░реЛрд╣реА",
+ "descending": "рдЕрд╡рд░реЛрд╣реА",
+ "description": "рд╕реВрдЪреА рдореЗрдВ рдЖрдЗрдЯрдо рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "removeDuplicates": "рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рд╣рдЯрд╛рдПрдВ",
+ "removeEmpty": "рдЦрд╛рд▓реА рдЖрдЗрдЯрдо рд╣рдЯрд╛рдПрдВ",
+ "resultTitle": "рдХреНрд░рдордмрджреНрдз рд╕реВрдЪреА",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "sortAlphabetically": "рд╡рд░реНрдгрд╛рдиреБрдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ",
+ "sortByLength": "рд▓рдВрдмрд╛рдИ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ",
+ "sortNumerically": "рд╕рдВрдЦреНрдпрд╛рддреНрдордХ рд░реВрдк рд╕реЗ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ",
+ "sortOrder": "рдХреНрд░рдордмрджреНрдз рдХрд░рдиреЗ рдХрд╛ рдХреНрд░рдо",
+ "sortingOptions": "рдХреНрд░рдордмрджреНрдз рдХрд░рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "title": "рд╕реВрдЪреА рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ",
+ "trimWhitespace": "рд╕рдлреЗрдж рд╕реНрдерд╛рди рдЯреНрд░рд┐рдо рдХрд░реЗрдВ"
+ },
+ "truncate": {
+ "description": "рд╕реВрдЪреА рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд▓рдВрдмрд╛рдИ рддрдХ рдХрд╛рдЯреЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "lengthPlaceholder": "рд▓рдВрдмрд╛рдИ",
+ "resultTitle": "рдХрд╛рдЯреА рдЧрдИ рд╕реВрдЪреА",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "рд╕реВрдЪреА рдХрд╛рдЯреЗрдВ",
+ "truncateFrom": "рдХрд╣рд╛рдБ рд╕реЗ рдХрд╛рдЯреЗрдВ",
+ "truncateFromEnd": "рдЕрдВрдд рд╕реЗ",
+ "truncateFromStart": "рд╢реБрд░реБрдЖрдд рд╕реЗ",
+ "truncateLength": "рдХрд╛рдЯрдиреЗ рдХреА рд▓рдВрдмрд╛рдИ",
+ "truncationOptions": "рдХрд╛рдЯрдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк"
+ },
+ "unwrap": {
+ "characterPlaceholder": "рд╡рд░реНрдг",
+ "description": "рд▓рдкреЗрдЯреА рдЧрдИ рд╕реВрдЪреА рдХреЛ рдЦреЛрд▓реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "removeEmpty": "рдЦрд╛рд▓реА рдЖрдЗрдЯрдо рд╣рдЯрд╛рдПрдВ",
+ "resultTitle": "рдЦреЛрд▓реА рдЧрдИ рд╕реВрдЪреА",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "рд╕реВрдЪреА рдЦреЛрд▓реЗрдВ",
+ "unwrapCharacter": "рдЦреЛрд▓рдиреЗ рдХрд╛ рд╡рд░реНрдг",
+ "unwrapOptions": "рдЦреЛрд▓рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк"
+ },
+ "wrap": {
+ "characterPlaceholder": "рд╡рд░реНрдг",
+ "description": "рд╕реВрдЪреА рдЖрдЗрдЯрдо рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд▓рдВрдмрд╛рдИ рдореЗрдВ рд▓рдкреЗрдЯреЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реВрдЪреА",
+ "resultTitle": "рд▓рдкреЗрдЯреА рдЧрдИ рд╕реВрдЪреА",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "title": "рд╕реВрдЪреА рд▓рдкреЗрдЯреЗрдВ",
+ "widthPlaceholder": "рдЪреМрдбрд╝рд╛рдИ",
+ "wrapCharacter": "рд▓рдкреЗрдЯрдиреЗ рдХрд╛ рд╡рд░реНрдг",
+ "wrapOptions": "рд▓рдкреЗрдЯрдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "wrapWidth": "рд▓рдкреЗрдЯрдиреЗ рдХреА рдЪреМрдбрд╝рд╛рдИ"
+ }
+}
diff --git a/public/locales/hi/number.json b/public/locales/hi/number.json
new file mode 100644
index 0000000..37803a9
--- /dev/null
+++ b/public/locales/hi/number.json
@@ -0,0 +1,45 @@
+{
+ "arithmeticSequence": {
+ "commonDifference": "рд╕рд╛рдорд╛рдиреНрдп рдЕрдВрддрд░",
+ "description": "рдЕрдВрдХрдЧрдгрд┐рддреАрдп рдЕрдиреБрдХреНрд░рдо рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВред",
+ "differencePlaceholder": "рдЕрдВрддрд░",
+ "firstTerm": "рдкрд╣рд▓рд╛ рдкрдж",
+ "firstTermPlaceholder": "рдкрдж",
+ "inputTitle": "рдЕрдиреБрдХреНрд░рдо",
+ "numberOfTerms": "рдкрджреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "resultTitle": "рдЕрдВрдХрдЧрдгрд┐рддреАрдп рдЕрдиреБрдХреНрд░рдо",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "sequenceOptions": "рдЕрдиреБрдХреНрд░рдо рд╡рд┐рдХрд▓реНрдк",
+ "termsPlaceholder": "рд╕рдВрдЦреНрдпрд╛",
+ "title": "рдЕрдВрдХрдЧрдгрд┐рддреАрдп рдЕрдиреБрдХреНрд░рдо"
+ },
+ "generate": {
+ "countNumbers": "рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреА рд╕рдВрдЦреНрдпрд╛",
+ "countPlaceholder": "рд╕рдВрдЦреНрдпрд╛",
+ "description": "рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреА рд╕реВрдЪреА рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВред",
+ "generationOptions": "рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "inputTitle": "рдЙрддреНрдкрдиреНрди рдХреА рдЧрдИ рд╕рдВрдЦреНрдпрд╛рдПрдВ",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "resultTitle": "рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреА рд╕реВрдЪреА",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "startNumber": "рд╢реБрд░реБрдЖрддреА рд╕рдВрдЦреНрдпрд╛",
+ "startPlaceholder": "рд╕рдВрдЦреНрдпрд╛",
+ "stepPlaceholder": "рдорд╛рди",
+ "stepValue": "рдЪрд░рдг рдорд╛рди",
+ "title": "рд╕рдВрдЦреНрдпрд╛рдПрдВ рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВ"
+ },
+ "sum": {
+ "description": "рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреА рд╕реВрдЪреА рдХрд╛ рдпреЛрдЧ рдХрд░реЗрдВред",
+ "ignoreNonNumbers": "рдЧреИрд░-рд╕рдВрдЦреНрдпрд╛рддреНрдордХ рдорд╛рди рдЕрдирджреЗрдЦрд╛ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕рдВрдЦреНрдпрд╛рдПрдВ",
+ "resultFormat": "рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рд░реВрдк",
+ "resultTitle": "рдпреЛрдЧ",
+ "separatorPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "showAverage": "рдФрд╕рдд рджрд┐рдЦрд╛рдПрдВ",
+ "showCount": "рдЧрдгрдирд╛ рджрд┐рдЦрд╛рдПрдВ",
+ "showSum": "рдпреЛрдЧ рджрд┐рдЦрд╛рдПрдВ",
+ "sumOptions": "рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "title": "рд╕рдВрдЦреНрдпрд╛рдПрдВ рдЬреЛрдбрд╝реЗрдВ"
+ }
+}
diff --git a/public/locales/hi/pdf.json b/public/locales/hi/pdf.json
new file mode 100644
index 0000000..30f541e
--- /dev/null
+++ b/public/locales/hi/pdf.json
@@ -0,0 +1,82 @@
+{
+ "compressPdf": {
+ "compressionLevel": "рд╕рдВрдкреАрдбрд╝рди рд╕реНрддрд░",
+ "compressionOptions": "рд╕рдВрдкреАрдбрд╝рди рд╡рд┐рдХрд▓реНрдк",
+ "description": "PDF рдлрд╝рд╛рдЗрд▓ рдЖрдХрд╛рд░ рдХрдо рдХрд░реЗрдВред",
+ "high": "рдЙрдЪреНрдЪ",
+ "imageQuality": "рдЫрд╡рд┐ рдЧреБрдгрд╡рддреНрддрд╛",
+ "inputTitle": "рдЗрдирдкреБрдЯ PDF",
+ "low": "рдХрдо",
+ "medium": "рдордзреНрдпрдо",
+ "qualityPlaceholder": "рдЧреБрдгрд╡рддреНрддрд╛ (1-100)",
+ "removeMetadata": "рдореЗрдЯрд╛рдбреЗрдЯрд╛ рд╣рдЯрд╛рдПрдВ",
+ "resultTitle": "рд╕рдВрдкреАрдбрд╝рд┐рдд PDF",
+ "title": "PDF рд╕рдВрдкреАрдбрд╝рд┐рдд рдХрд░реЗрдВ"
+ },
+ "mergePdf": {
+ "customOrder": "рдХрд╕реНрдЯрдо рдХреНрд░рдо",
+ "description": "рдХрдИ PDF рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдПрдХ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред",
+ "includeBookmarks": "рдмреБрдХрдорд╛рд░реНрдХ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ PDF рдлрд╝рд╛рдЗрд▓реЗрдВ",
+ "mergeOptions": "рдорд░реНрдЬ рд╡рд┐рдХрд▓реНрдк",
+ "mergeOrder": "рдорд░реНрдЬ рдХреНрд░рдо",
+ "orderByFilename": "рдлрд╝рд╛рдЗрд▓ рдирд╛рдо рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдХреНрд░рдо",
+ "orderByUpload": "рдЕрдкрд▓реЛрдб рдХреНрд░рдо рдХреЗ рдЕрдиреБрд╕рд╛рд░",
+ "resultTitle": "рдорд░реНрдЬ рдХрд┐рдпрд╛ рдЧрдпрд╛ PDF",
+ "title": "PDF рдорд░реНрдЬ рдХрд░реЗрдВ"
+ },
+ "pdfToEpub": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "PDF рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдХреЛ EPUB рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "extractImages": "рдЫрд╡рд┐рдпрд╛рдВ рдирд┐рдХрд╛рд▓реЗрдВ",
+ "generateToc": "рд╕рд╛рдордЧреНрд░реА рддрд╛рд▓рд┐рдХрд╛ рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ PDF",
+ "preserveFormatting": "рдлреЙрд░реНрдореЗрдЯрд┐рдВрдЧ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "resultTitle": "EPUB рдлрд╝рд╛рдЗрд▓",
+ "title": "PDF рд╕реЗ EPUB"
+ },
+ "protectPdf": {
+ "allowCopying": "рдХреЙрдкреА рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдВ",
+ "allowModification": "рд╕рдВрд╢реЛрдзрди рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдВ",
+ "allowPrinting": "рдкреНрд░рд┐рдВрдЯрд┐рдВрдЧ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдВ",
+ "description": "PDF рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдкрд╛рд╕рд╡рд░реНрдб рд╕реБрд░рдХреНрд╖рд╛ рдЬреЛрдбрд╝реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ PDF",
+ "ownerPassword": "рдорд╛рд▓рд┐рдХ рдкрд╛рд╕рд╡рд░реНрдб",
+ "ownerPasswordPlaceholder": "рдкрд╛рд╕рд╡рд░реНрдб",
+ "permissions": "рдЕрдиреБрдорддрд┐рдпрд╛рдВ",
+ "protectionOptions": "рд╕реБрд░рдХреНрд╖рд╛ рд╡рд┐рдХрд▓реНрдк",
+ "resultTitle": "рд╕реБрд░рдХреНрд╖рд┐рдд PDF",
+ "title": "PDF рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "userPassword": "рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкрд╛рд╕рд╡рд░реНрдб",
+ "userPasswordPlaceholder": "рдкрд╛рд╕рд╡рд░реНрдб"
+ },
+ "rotatePdf": {
+ "angle180": "180 рдбрд┐рдЧреНрд░реА",
+ "angle270": "270 рдбрд┐рдЧреНрд░реА",
+ "angle90": "90 рдбрд┐рдЧреНрд░реА",
+ "applyToAll": "рд╕рднреА рдкреЗрдЬреЛрдВ рдкрд░ рд▓рд╛рдЧреВ рдХрд░реЗрдВ",
+ "applyToSelected": "рдЪрдпрдирд┐рдд рдкреЗрдЬреЛрдВ рдкрд░ рд▓рд╛рдЧреВ рдХрд░реЗрдВ",
+ "description": "PDF рдкреЗрдЬреЛрдВ рдХреЛ рдШреБрдорд╛рдПрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ PDF",
+ "pagesPlaceholder": "рдЬреИрд╕реЗ 1,3-5,7",
+ "resultTitle": "рдШреБрдорд╛рдпрд╛ рдЧрдпрд╛ PDF",
+ "rotationAngle": "рдШреБрдорд╛рдиреЗ рдХрд╛ рдХреЛрдг",
+ "rotationOptions": "рдШреБрдорд╛рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "selectedPages": "рдЪрдпрдирд┐рдд рдкреЗрдЬ",
+ "title": "PDF рдШреБрдорд╛рдПрдВ"
+ },
+ "splitPdf": {
+ "description": "PDF рдлрд╝рд╛рдЗрд▓ рд╕реЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреЗрдЬ рдирд┐рдХрд╛рд▓реЗрдВред",
+ "includeBookmarks": "рдмреБрдХрдорд╛рд░реНрдХ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ PDF",
+ "pageRanges": "рдкреЗрдЬ рд╢реНрд░реЗрдгрд┐рдпрд╛рдВ",
+ "rangesPlaceholder": "рдЬреИрд╕реЗ 1,3-5,7",
+ "resultTitle": "рд╡рд┐рднрд╛рдЬрд┐рдд PDF рдлрд╝рд╛рдЗрд▓реЗрдВ",
+ "splitByBookmarks": "рдмреБрдХрдорд╛рд░реНрдХ рджреНрд╡рд╛рд░рд╛ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ",
+ "splitByPages": "рдкреЗрдЬ рджреНрд╡рд╛рд░рд╛ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ",
+ "splitByRanges": "рд╢реНрд░реЗрдгрд┐рдпреЛрдВ рджреНрд╡рд╛рд░рд╛ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ",
+ "splitMethod": "рд╡рд┐рднрд╛рдЬрди рд╡рд┐рдзрд┐",
+ "splitOptions": "рд╡рд┐рднрд╛рдЬрди рд╡рд┐рдХрд▓реНрдк",
+ "title": "PDF рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ"
+ }
+}
diff --git a/public/locales/hi/string.json b/public/locales/hi/string.json
new file mode 100644
index 0000000..9bdf97b
--- /dev/null
+++ b/public/locales/hi/string.json
@@ -0,0 +1,196 @@
+{
+ "base64": {
+ "decode": "рдмреЗрд╕64 рдбрд┐рдХреЛрдб",
+ "description": "рдмреЗрд╕64 рдПрдирдХреЛрдбрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдПрдирдХреЛрдб рдпрд╛ рдбрд┐рдХреЛрдб рдХрд░реЗрдВред",
+ "encode": "рдмреЗрд╕64 рдПрдирдХреЛрдб",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛",
+ "optionsTitle": "рдмреЗрд╕64 рд╡рд┐рдХрд▓реНрдк",
+ "resultTitle": "рдкрд░рд┐рдгрд╛рдо",
+ "title": "рдмреЗрд╕64 рдПрдирдХреЛрдбрд░/рдбрд┐рдХреЛрдбрд░",
+ "toolInfo": {
+ "description": "рдмреЗрд╕64 рдПрдХ рдПрдирдХреЛрдбрд┐рдВрдЧ рдпреЛрдЬрдирд╛ рд╣реИ рдЬреЛ рдбреЗрдЯрд╛ рдХреЛ рд░реЗрдбрд┐рдХреНрд╕-64 рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдХрд░рдХреЗ ASCII рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреА рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреЛ рдПрдирдХреЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдпрд╣ рдЖрдорддреМрд░ рдкрд░ рдмрд╛рдЗрдирд░реА рдбреЗрдЯрд╛ рдХреЛ рдПрдирдХреЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬреЛ рдЯреЗрдХреНрд╕реНрдЯ рдбреЗрдЯрд╛ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдП рдЧрдП рдореАрдбрд┐рдпрд╛ рдкрд░ рдкреНрд░рд╕рд╛рд░рдг рдХреЗ рд▓рд┐рдП рд╣реЛрддрд╛ рд╣реИред",
+ "title": "рдмреЗрд╕64 рдХреНрдпрд╛ рд╣реИ?"
+ }
+ },
+ "join": {
+ "blankLinesAndTrailingSpaces": "рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпрд╛рдВ рдФрд░ рдЕрдиреБрдЧрд╛рдореА рд╕реНрдерд╛рди",
+ "deleteBlankDescription": "рдЙрди рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд╣рдЯрд╛рдПрдВ рдЬрд┐рдирдореЗрдВ рдЯреЗрдХреНрд╕реНрдЯ рдкреНрд░рддреАрдХ рдирд╣реАрдВ рд╣реИрдВред",
+ "deleteBlankTitle": "рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпрд╛рдВ рд╣рдЯрд╛рдПрдВ",
+ "deleteTrailingDescription": "рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЗ рдЕрдВрдд рд╕реЗ рд╕реНрдкреЗрд╕ рдФрд░ рдЯреИрдм рд╣рдЯрд╛рдПрдВред",
+ "deleteTrailingTitle": "рдЕрдиреБрдЧрд╛рдореА рд╕реНрдерд╛рди рд╣рдЯрд╛рдПрдВ",
+ "description": "рдХрд╕реНрдЯрдорд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╡рд┐рднрд╛рдЬрдХреЛрдВ рдХреЗ рд╕рд╛рде рдЯреЗрдХреНрд╕реНрдЯ рдЯреБрдХрдбрд╝реЛрдВ рдХреЛ рдПрдХ рд╕рд╛рде рдЬреЛрдбрд╝реЗрдВред",
+ "inputTitle": "рдЯреЗрдХреНрд╕реНрдЯ рдЯреБрдХрдбрд╝реЗ",
+ "joinCharacterDescription": "рдкреНрд░рддреАрдХ рдЬреЛ рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рдЯреВрдЯреЗ рд╣реБрдП рдЯреБрдХрдбрд╝реЛрдВ рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реИред (рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рд╕реНрдкреЗрд╕ред)",
+ "joinCharacterPlaceholder": "рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рд╡рд░реНрдг",
+ "resultTitle": "рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рдЯреЗрдХреНрд╕реНрдЯ",
+ "textMergedOptions": "рдЯреЗрдХреНрд╕реНрдЯ рдорд░реНрдЬ рд╡рд┐рдХрд▓реНрдк",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдЬреЛрдбрд╝реЗрдВ",
+ "toolInfo": {
+ "description": "рдЗрд╕ рдЯреВрд▓ рдХреЗ рд╕рд╛рде рдЖрдк рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рднрд╛рдЧреЛрдВ рдХреЛ рдПрдХ рд╕рд╛рде рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдирдИ рдкрдВрдХреНрддрд┐рдпреЛрдВ рд╕реЗ рдЕрд▓рдЧ рдХрд┐рдП рдЧрдП рдЯреЗрдХреНрд╕реНрдЯ рдореВрд▓реНрдпреЛрдВ рдХреА рд╕реВрдЪреА рд▓реЗрддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдПрдХ рд╕рд╛рде рдорд░реНрдЬ рдХрд░рддрд╛ рд╣реИред рдЖрдк рдЙрд╕ рд╡рд░реНрдг рдХреЛ рд╕реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рд╕рдВрдпреБрдХреНрдд рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рднрд╛рдЧреЛрдВ рдХреЗ рдмреАрдЪ рд░рдЦрд╛ рдЬрд╛рдПрдЧрд╛ред рд╕рд╛рде рд╣реА, рдЖрдк рд╕рднреА рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЕрдирджреЗрдЦрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╕рднреА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЗ рдЕрдВрдд рд╕реЗ рд╕реНрдкреЗрд╕ рдФрд░ рдЯреИрдм рд╣рдЯрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдЯреЗрдХреНрд╕реНрдЯрд╛рдмреБрд▓рд╕!",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдЬреЛрдЗрдирд░ рдХреНрдпрд╛ рд╣реИ?"
+ }
+ },
+ "quote": {
+ "allowDoubleQuotation": "рджреЛрд╣рд░реЗ рдЙрджреНрдзрд░рдг рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдВ",
+ "description": "рдХрд╕реНрдЯрдорд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рд╕рд╛рде рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рдЪрд╛рд░реЛрдВ рдУрд░ рдЙрджреНрдзрд░рдг рдЬреЛрдбрд╝реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЯреЗрдХреНрд╕реНрдЯ",
+ "leftQuoteDescription": "рдмрд╛рдПрдВ рдЙрджреНрдзрд░рдг рд╡рд░реНрдг",
+ "processAsMultiLine": "рдмрд╣реБ-рдкрдВрдХреНрддрд┐ рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░реЗрдВ",
+ "quoteEmptyLines": "рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдХреЛрдЯ рдХрд░реЗрдВ",
+ "quoteOptions": "рдЙрджреНрдзрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "resultTitle": "рдХреЛрдЯреЗрдб рдЯреЗрдХреНрд╕реНрдЯ",
+ "rightQuoteDescription": "рджрд╛рдПрдВ рдЙрджреНрдзрд░рдг рд╡рд░реНрдг",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛрдЯрд░",
+ "toolInfo": {
+ "description": "рдпрд╣ рдЯреВрд▓ рдЖрдкрдХреЛ рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рдЪрд╛рд░реЛрдВ рдУрд░ рдЙрджреНрдзрд░рдг рдЬреЛрдбрд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЖрдк рд╡рд┐рднрд┐рдиреНрди рдЙрджреНрдзрд░рдг рд╡рд░реНрдг рдЪреБрди рд╕рдХрддреЗ рд╣реИрдВ, рдмрд╣реБ-рдкрдВрдХреНрддрд┐ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рд╕рдВрднрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдХреИрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЯреЗрдХреНрд╕реНрдЯ рддреИрдпрд╛рд░ рдХрд░рдиреЗ, рдбреЗрдЯрд╛ рдХреЛ рдлреЙрд░реНрдореЗрдЯ рдХрд░рдиреЗ, рдпрд╛ рд╕реНрдЯрд╛рдЗрд▓рд┐рд╢ рдЯреЗрдХреНрд╕реНрдЯ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реИред",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛрдЯрд░"
+ }
+ },
+ "repeat": {
+ "delimiterDescription": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рддрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд╛рдЬрдХред",
+ "delimiterPlaceholder": "рд╡рд┐рднрд╛рдЬрдХ",
+ "description": "рдХрд╕реНрдЯрдорд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╡рд┐рднрд╛рдЬрдХреЛрдВ рдХреЗ рд╕рд╛рде рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдХрдИ рдмрд╛рд░ рджреЛрд╣рд░рд╛рдПрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЯреЗрдХреНрд╕реНрдЯ",
+ "numberPlaceholder": "рд╕рдВрдЦреНрдпрд╛",
+ "repeatAmountDescription": "рджреЛрд╣рд░рд╛рд╡ рдХреА рд╕рдВрдЦреНрдпрд╛ред",
+ "repetitionsDelimiter": "рджреЛрд╣рд░рд╛рд╡ рд╡рд┐рднрд╛рдЬрдХ",
+ "resultTitle": "рджреЛрд╣рд░рд╛рдпрд╛ рдЧрдпрд╛ рдЯреЗрдХреНрд╕реНрдЯ",
+ "textRepetitions": "рдЯреЗрдХреНрд╕реНрдЯ рджреЛрд╣рд░рд╛рд╡",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рджреЛрд╣рд░рд╛рдПрдВ",
+ "toolInfo": {
+ "description": "рдпрд╣ рдЯреВрд▓ рдЖрдкрдХреЛ рд╡реИрдХрд▓реНрдкрд┐рдХ рд╡рд┐рднрд╛рдЬрдХ рдХреЗ рд╕рд╛рде рджрд┐рдП рдЧрдП рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдХрдИ рдмрд╛рд░ рджреЛрд╣рд░рд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рджреЛрд╣рд░рд╛рдПрдВ"
+ }
+ },
+ "reverse": {
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рд╡рд░реНрдгреЛрдВ рдХреЗ рдХреНрд░рдо рдХреЛ рдЙрд▓рдЯрд╛ рдХрд░реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЯреЗрдХреНрд╕реНрдЯ",
+ "processMultiLine": "рдмрд╣реБ-рдкрдВрдХреНрддрд┐ рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░реЗрдВ (рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдХреЛ рдЕрд▓рдЧ рд╕реЗ рдЙрд▓рдЯрд╛ рдХрд░реЗрдВ)",
+ "resultTitle": "рдЙрд▓рдЯрд╛ рдЯреЗрдХреНрд╕реНрдЯ",
+ "skipEmptyLines": "рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЫреЛрдбрд╝реЗрдВ",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдЙрд▓рдЯрд╛ рдХрд░реЗрдВ",
+ "trimWhitespace": "рдкрдВрдХреНрддрд┐рдпреЛрдВ рд╕реЗ рд╕рдлреЗрдж рд╕реНрдерд╛рди рдЯреНрд░рд┐рдо рдХрд░реЗрдВ"
+ },
+ "rot13": {
+ "description": "ROT13 рд╕рд┐рдлрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдПрдирдХреЛрдб рдпрд╛ рдбрд┐рдХреЛрдб рдХрд░реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЯреЗрдХреНрд╕реНрдЯ",
+ "resultTitle": "ROT13 рдкрд░рд┐рдгрд╛рдо",
+ "title": "ROT13 рдПрдирдХреЛрдбрд░/рдбрд┐рдХреЛрдбрд░",
+ "toolInfo": {
+ "description": "ROT13 (13 рд╕реНрдерд╛рдиреЛрдВ рд╕реЗ рдШреБрдорд╛рдПрдВ) рдПрдХ рд╕рд░рд▓ рдЕрдХреНрд╖рд░ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рд╕рд┐рдлрд░ рд╣реИ рдЬреЛ рдПрдХ рдЕрдХреНрд╖рд░ рдХреЛ рд╡рд░реНрдгрдорд╛рд▓рд╛ рдореЗрдВ рдЙрд╕рдХреЗ рдмрд╛рдж рдХреЗ 13рд╡реЗрдВ рдЕрдХреНрд╖рд░ рд╕реЗ рдмрджрд▓ рджреЗрддрд╛ рд╣реИред ROT13 рд╕реАрдЬрд╝рд░ рд╕рд┐рдлрд░ рдХрд╛ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓рд╛ рд╣реИ рдЬреЛ рдкреНрд░рд╛рдЪреАрди рд░реЛрдо рдореЗрдВ рд╡рд┐рдХрд╕рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдХреНрдпреЛрдВрдХрд┐ рдЕрдВрдЧреНрд░реЗрдЬреА рд╡рд░реНрдгрдорд╛рд▓рд╛ рдореЗрдВ 26 рдЕрдХреНрд╖рд░ рд╣реИрдВ, ROT13 рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рд╡реНрдпреБрддреНрдХреНрд░рдо рд╣реИ; рдЕрд░реНрдерд╛рдд, ROT13 рдХреЛ рдкреВрд░реНрд╡рд╡рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рд╣реА рдПрд▓реНрдЧреЛрд░рд┐рдердо рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдПрдирдХреЛрдбрд┐рдВрдЧ рдФрд░ рдбрд┐рдХреЛрдбрд┐рдВрдЧ рджреЛрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реА рдХреНрд░рд┐рдпрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред",
+ "title": "ROT13 рдХреНрдпрд╛ рд╣реИ?"
+ }
+ },
+ "rotate": {
+ "description": "рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реНрдерд╛рдиреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рд╡рд░реНрдгреЛрдВ рдХреЛ рдШреБрдорд╛рдПрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЯреЗрдХреНрд╕реНрдЯ",
+ "processAsMultiLine": "рдмрд╣реБ-рдкрдВрдХреНрддрд┐ рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░реЗрдВ (рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдХреЛ рдЕрд▓рдЧ рд╕реЗ рдШреБрдорд╛рдПрдВ)",
+ "resultTitle": "рдШреБрдорд╛рдпрд╛ рдЧрдпрд╛ рдЯреЗрдХреНрд╕реНрдЯ",
+ "rotateLeft": "рдмрд╛рдИрдВ рдУрд░ рдШреБрдорд╛рдПрдВ",
+ "rotateRight": "рджрд╛рдИрдВ рдУрд░ рдШреБрдорд╛рдПрдВ",
+ "rotationOptions": "рдШреБрдорд╛рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "stepDescription": "рдШреБрдорд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рдиреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдШреБрдорд╛рдПрдВ",
+ "toolInfo": {
+ "description": "рдпрд╣ рдЯреВрд▓ рдЖрдкрдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╕реНрдерд╛рдиреЛрдВ рджреНрд╡рд╛рд░рд╛ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рд╡рд░реНрдгреЛрдВ рдХреЛ рдШреБрдорд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЖрдк рдмрд╛рдПрдВ рдпрд╛ рджрд╛рдПрдВ рдШреБрдорд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдХреЛ рдЕрд▓рдЧ рд╕реЗ рдШреБрдорд╛рдХрд░ рдмрд╣реБ-рдкрдВрдХреНрддрд┐ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕реНрдЯреНрд░рд┐рдВрдЧ рд░реЛрдЯреЗрд╢рди рд╕рд░рд▓ рдЯреЗрдХреНрд╕реНрдЯ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ, рдкреИрдЯрд░реНрди рдмрдирд╛рдиреЗ, рдпрд╛ рдмреБрдирд┐рдпрд╛рджреА рдПрдиреНрдХреНрд░рд┐рдкреНрд╢рди рддрдХрдиреАрдХреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реИред",
+ "title": "рд╕реНрдЯреНрд░рд┐рдВрдЧ рд░реЛрдЯреЗрд╢рди"
+ }
+ },
+ "split": {
+ "charAfterChunkDescription": "рдкреНрд░рддреНрдпреЗрдХ рдЪрдВрдХ рдХреЗ рдмрд╛рдж рд╡рд░реНрдг",
+ "charBeforeChunkDescription": "рдкреНрд░рддреНрдпреЗрдХ рдЪрдВрдХ рд╕реЗ рдкрд╣рд▓реЗ рд╡рд░реНрдг",
+ "chunksDescription": "рдЖрдЙрдЯрдкреБрдЯ рдореЗрдВ рд╕рдорд╛рди рд▓рдВрдмрд╛рдИ рдХреЗ рдЪрдВрдХ рдХреА рд╕рдВрдЦреНрдпрд╛ред",
+ "chunksTitle": "рдЪрдВрдХ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ",
+ "description": "рд╡рд┐рднрд┐рдиреНрди рдорд╛рдирджрдВрдбреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рднрд╛рдЧреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВред",
+ "lengthDescription": "рдкреНрд░рддреНрдпреЗрдХ рдЖрдЙрдЯрдкреБрдЯ рдЪрдВрдХ рдореЗрдВ рд░рдЦреЗ рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рд╡рд░реНрдгреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ред",
+ "lengthTitle": "рд╡рд┐рднрд╛рдЬрди рдХреЗ рд▓рд┐рдП рд▓рдВрдмрд╛рдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ",
+ "outputSeparatorDescription": "рд╡рд░реНрдг рдЬреЛ рд╡рд┐рднрд╛рдЬрд┐рдд рдЪрдВрдХ рдХреЗ рдмреАрдЪ рд░рдЦрд╛ рдЬрд╛рдПрдЧрд╛ред (рдпрд╣ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдирдИ рдкрдВрдХреНрддрд┐ \"\\n\" рд╣реИред)",
+ "outputSeparatorOptions": "рдЖрдЙрдЯрдкреБрдЯ рд╡рд┐рднрд╛рдЬрдХ рд╡рд┐рдХрд▓реНрдк",
+ "regexDescription": "рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдЬреЛ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рднрд╛рдЧреЛрдВ рдореЗрдВ рддреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдПрдЧреАред (рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдХрдИ рд╕реНрдкреЗрд╕ред)",
+ "regexTitle": "рд╡рд┐рднрд╛рдЬрди рдХреЗ рд▓рд┐рдП рд░реЗрдЧреЗрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ",
+ "resultTitle": "рдЯреЗрдХреНрд╕реНрдЯ рдЯреБрдХрдбрд╝реЗ",
+ "splitSeparatorOptions": "рд╡рд┐рднрд╛рдЬрдХ рд╡рд┐рдХрд▓реНрдк",
+ "symbolDescription": "рд╡рд░реНрдг рдЬреЛ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рднрд╛рдЧреЛрдВ рдореЗрдВ рддреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред (рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рд╕реНрдкреЗрд╕ред)",
+ "symbolTitle": "рд╡рд┐рднрд╛рдЬрди рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ"
+ },
+ "statistic": {
+ "characterFrequencyAnalysis": "рд╡рд░реНрдг рдЖрд╡реГрддреНрддрд┐ рд╡рд┐рд╢реНрд▓реЗрд╖рдг",
+ "characterFrequencyAnalysisDescription": "рдЧрдгрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рд╡рд░реНрдг рдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рдХрд┐рддрдиреА рдмрд╛рд░ рджрд┐рдЦрд╛рдИ рджреЗрддрд╛ рд╣реИ",
+ "delimitersOptions": "рд╡рд┐рднрд╛рдЬрдХ рд╡рд┐рдХрд▓реНрдк",
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВ рдФрд░ рд╡реНрдпрд╛рдкрдХ рдЖрдВрдХрдбрд╝реЗ рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВред",
+ "includeEmptyLines": "рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпрд╛рдВ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "includeEmptyLinesDescription": "рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреА рдЧрдгрдирд╛ рдХрд░рддреЗ рд╕рдордп рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпрд╛рдВ рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЯреЗрдХреНрд╕реНрдЯ",
+ "resultTitle": "рдЯреЗрдХреНрд╕реНрдЯ рдЖрдВрдХрдбрд╝реЗ",
+ "sentenceDelimitersDescription": "рдЕрдкрдиреА рднрд╛рд╖рд╛ рдореЗрдВ рд╡рд╛рдХреНрдпреЛрдВ рдХреЛ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдХрд╕реНрдЯрдо рд╡рд░реНрдг рджрд░реНрдЬ рдХрд░реЗрдВ (рдХреЙрдорд╛ рд╕реЗ рдЕрд▓рдЧ) рдпрд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ рдЦрд╛рд▓реА рдЫреЛрдбрд╝ рджреЗрдВред",
+ "sentenceDelimitersPlaceholder": "рдЬреИрд╕реЗ ., !, ?, ...",
+ "statisticsOptions": "рдЖрдВрдХрдбрд╝реЗ рд╡рд┐рдХрд▓реНрдк",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдЖрдВрдХрдбрд╝реЗ",
+ "toolInfo": {
+ "description": "рдпрд╣ рдЯреВрд▓ рдЖрдкрдХреЛ рдЯреЗрдХреНрд╕реНрдЯ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдФрд░ рд╡рд░реНрдг рдЧрдгрдирд╛, рд╢рдмреНрдж рдЧрдгрдирд╛, рдкрдВрдХреНрддрд┐ рдЧрдгрдирд╛, рдФрд░ рд╡рд░реНрдгреЛрдВ рдФрд░ рд╢рдмреНрджреЛрдВ рдХреЗ рдЖрд╡реГрддреНрддрд┐ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рд╕рд╣рд┐рдд рд╡реНрдпрд╛рдкрдХ рдЖрдВрдХрдбрд╝реЗ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред",
+ "title": "{{title}} рдХреНрдпрд╛ рд╣реИ?"
+ },
+ "wordDelimitersDescription": "рд╢рдмреНрджреЛрдВ рдХреА рдЧрдгрдирд╛ рдХреЗ рд▓рд┐рдП рдХрд╕реНрдЯрдо рд░реЗрдЧреЗрдХреНрд╕ рджрд░реНрдЬ рдХрд░реЗрдВ рдпрд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ рдЦрд╛рд▓реА рдЫреЛрдбрд╝ рджреЗрдВред",
+ "wordDelimitersPlaceholder": "рдЬреИрд╕реЗ \\s.,;:!?\"┬л┬╗()тАж",
+ "wordFrequencyAnalysis": "рд╢рдмреНрдж рдЖрд╡реГрддреНрддрд┐ рд╡рд┐рд╢реНрд▓реЗрд╖рдг",
+ "wordFrequencyAnalysisDescription": "рдЧрдгрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рд╢рдмреНрдж рдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рдХрд┐рддрдиреА рдмрд╛рд░ рджрд┐рдЦрд╛рдИ рджреЗрддрд╛ рд╣реИ"
+ },
+ "textReplacer": {
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдкреИрдЯрд░реНрди рдХреЛ рдирдИ рд╕рд╛рдордЧреНрд░реА рд╕реЗ рдмрджрд▓реЗрдВред",
+ "findPatternInText": "рдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рдпрд╣ рдкреИрдЯрд░реНрди рдЦреЛрдЬреЗрдВ",
+ "findPatternUsingRegexp": "рд░реЗрдЧреЗрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреИрдЯрд░реНрди рдЦреЛрдЬреЗрдВ",
+ "inputTitle": "рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреЗрдХреНрд╕реНрдЯ",
+ "newTextPlaceholder": "рдирдпрд╛ рдЯреЗрдХреНрд╕реНрдЯ",
+ "regexpDescription": "рдЙрд╕ рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЛ рджрд░реНрдЬ рдХрд░реЗрдВ рдЬрд┐рд╕реЗ рдЖрдк рдмрджрд▓рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред",
+ "replacePatternDescription": "рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреИрдЯрд░реНрди рджрд░реНрдЬ рдХрд░реЗрдВред",
+ "replaceText": "рдЯреЗрдХреНрд╕реНрдЯ рдмрджрд▓реЗрдВ",
+ "resultTitle": "рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдХреЗ рд╕рд╛рде рдЯреЗрдХреНрд╕реНрдЯ",
+ "searchPatternDescription": "рдЙрд╕ рдЯреЗрдХреНрд╕реНрдЯ рдкреИрдЯрд░реНрди рдХреЛ рджрд░реНрдЬ рдХрд░реЗрдВ рдЬрд┐рд╕реЗ рдЖрдк рдмрджрд▓рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред",
+ "searchText": "рдЦреЛрдЬ рдЯреЗрдХреНрд╕реНрдЯ",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рд░рд┐рдкреНрд▓реЗрд╕рд░",
+ "toolInfo": {
+ "description": "рдЗрд╕ рд╕рд░рд▓, рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдЯреВрд▓ рдХреЗ рд╕рд╛рде рдЕрдкрдиреА рд╕рд╛рдордЧреНрд░реА рдореЗрдВ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рдмрджрд▓реЗрдВред рдмрд╕ рдЕрдкрдирд╛ рдЯреЗрдХреНрд╕реНрдЯ рдЗрдирдкреБрдЯ рдХрд░реЗрдВ, рдЙрд╕ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рд╕реЗрдЯ рдХрд░реЗрдВ рдЬрд┐рд╕реЗ рдЖрдк рдмрджрд▓рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдореВрд▓реНрдп, рдФрд░ рддреБрд░рдВрдд рдЕрдкрдбреЗрдЯреЗрдб рд╕рдВрд╕реНрдХрд░рдг рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рд░рд┐рдкреНрд▓реЗрд╕рд░"
+ }
+ },
+ "toMorse": {
+ "dashSymbolDescription": "рдкреНрд░рддреАрдХ рдЬреЛ рдореЛрд░реНрд╕ рдХреЛрдб рдореЗрдВ рдбреИрд╢ рдХреЗ рдЕрдиреБрд░реВрдк рд╣реЛрдЧрд╛ред",
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдореЛрд░реНрд╕ рдХреЛрдб рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "dotSymbolDescription": "рдкреНрд░рддреАрдХ рдЬреЛ рдореЛрд░реНрд╕ рдХреЛрдб рдореЗрдВ рдбреЙрдЯ рдХреЗ рдЕрдиреБрд░реВрдк рд╣реЛрдЧрд╛ред",
+ "longSignal": "рд▓рдВрдмрд╛ рд╕рдВрдХреЗрдд",
+ "resultTitle": "рдореЛрд░реНрд╕ рдХреЛрдб",
+ "shortSignal": "рдЫреЛрдЯрд╛ рд╕рдВрдХреЗрдд",
+ "title": "рдореЛрд░реНрд╕ рдореЗрдВ"
+ },
+ "truncate": {
+ "addTruncationIndicator": "рдХрд╛рдЯрдиреЗ рдХрд╛ рд╕рдВрдХреЗрддрдХ рдЬреЛрдбрд╝реЗрдВ",
+ "charactersPlaceholder": "рд╡рд░реНрдг",
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд▓рдВрдмрд╛рдИ рддрдХ рдЫреЛрдЯрд╛ рдХрд░реЗрдВред",
+ "indicatorDescription": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рдЕрдВрдд (рдпрд╛ рд╢реБрд░реБрдЖрдд) рдореЗрдВ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд░реНрдгред рдиреЛрдЯ: рд╡реЗ рд▓рдВрдмрд╛рдИ рдХреА рдУрд░ рдЧрд┐рдиреЗ рдЬрд╛рддреЗ рд╣реИрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЯреЗрдХреНрд╕реНрдЯ",
+ "leftSideDescription": "рдЯреЗрдХреНрд╕реНрдЯ рдХреА рд╢реБрд░реБрдЖрдд рд╕реЗ рд╡рд░реНрдг рд╣рдЯрд╛рдПрдВред",
+ "leftSideTruncation": "рдмрд╛рдИрдВ рддрд░рдл рдХрд╛рдЯрдирд╛",
+ "lengthAndLines": "рд▓рдВрдмрд╛рдИ рдФрд░ рдкрдВрдХреНрддрд┐рдпрд╛рдВ",
+ "lineByLineDescription": "рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдХреЛ рдЕрд▓рдЧ рд╕реЗ рдХрд╛рдЯреЗрдВред",
+ "lineByLineTruncating": "рдкрдВрдХреНрддрд┐ рджрд░ рдкрдВрдХреНрддрд┐ рдХрд╛рдЯрдирд╛",
+ "maxLengthDescription": "рдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рдЫреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд░реНрдгреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ред",
+ "numberPlaceholder": "рд╕рдВрдЦреНрдпрд╛",
+ "resultTitle": "рдХрд╛рдЯрд╛ рдЧрдпрд╛ рдЯреЗрдХреНрд╕реНрдЯ",
+ "rightSideDescription": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рдЕрдВрдд рд╕реЗ рд╡рд░реНрдг рд╣рдЯрд╛рдПрдВред",
+ "rightSideTruncation": "рджрд╛рдИрдВ рддрд░рдл рдХрд╛рдЯрдирд╛",
+ "suffixAndAffix": "рдкреНрд░рддреНрдпрдп рдФрд░ рдЙрдкрд╕рд░реНрдЧ",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдХрд╛рдЯреЗрдВ",
+ "toolInfo": {
+ "description": "рдмрд╛рдИрдВ рдУрд░ рдЗрдирдкреБрдЯ рдлреЙрд░реНрдо рдореЗрдВ рдЕрдкрдирд╛ рдЯреЗрдХреНрд╕реНрдЯ рд▓реЛрдб рдХрд░реЗрдВ рдФрд░ рдЖрдкрдХреЛ рджрд╛рдИрдВ рдУрд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдХрд╛рдЯрд╛ рдЧрдпрд╛ рдЯреЗрдХреНрд╕реНрдЯ рдорд┐рд▓реЗрдЧрд╛ред",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдХрд╛рдЯреЗрдВ"
+ },
+ "truncationSide": "рдХрд╛рдЯрдиреЗ рдХреА рддрд░рдл"
+ },
+ "uppercase": {
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдмрдбрд╝реЗ рдЕрдХреНрд╖рд░реЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдЯреЗрдХреНрд╕реНрдЯ",
+ "resultTitle": "рдмрдбрд╝реЗ рдЕрдХреНрд╖рд░реЛрдВ рдореЗрдВ рдЯреЗрдХреНрд╕реНрдЯ",
+ "title": "рдмрдбрд╝реЗ рдЕрдХреНрд╖рд░реЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВ"
+ }
+}
diff --git a/public/locales/hi/time.json b/public/locales/hi/time.json
new file mode 100644
index 0000000..b67bc6f
--- /dev/null
+++ b/public/locales/hi/time.json
@@ -0,0 +1,105 @@
+{
+ "checkLeapYears": {
+ "checkMultiple": "рдХрдИ рд╡рд░реНрд╖ рдЬрд╛рдВрдЪреЗрдВ",
+ "checkOptions": "рдЬрд╛рдВрдЪ рд╡рд┐рдХрд▓реНрдк",
+ "description": "рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╡рд░реНрд╖реЛрдВ рдХреЛ рд▓реАрдк рд╡рд░реНрд╖ рдХреЗ рд░реВрдк рдореЗрдВ рдЬрд╛рдВрдЪреЗрдВред",
+ "endPlaceholder": "рд╡рд░реНрд╖",
+ "endYear": "рдЕрдВрддрд┐рдо рд╡рд░реНрд╖",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡рд░реНрд╖",
+ "resultTitle": "рд▓реАрдк рд╡рд░реНрд╖ рдкрд░рд┐рдгрд╛рдо",
+ "startPlaceholder": "рд╡рд░реНрд╖",
+ "startYear": "рд╢реБрд░реБрдЖрддреА рд╡рд░реНрд╖",
+ "title": "рд▓реАрдк рд╡рд░реНрд╖ рдЬрд╛рдВрдЪреЗрдВ",
+ "yearRange": "рд╡рд░реНрд╖ рд╢реНрд░реЗрдгреА"
+ },
+ "convertDaysToHours": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "decimalPlaces": "рджрд╢рдорд▓рд╡ рд╕реНрдерд╛рди",
+ "description": "рджрд┐рдиреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдШрдВрдЯреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рджрд┐рди",
+ "placesPlaceholder": "рд╕реНрдерд╛рди",
+ "resultTitle": "рдШрдВрдЯреЗ",
+ "showBreakdown": "рд╡рд┐рд╕реНрддреГрдд рд╡рд┐рд╡рд░рдг рджрд┐рдЦрд╛рдПрдВ",
+ "title": "рджрд┐рдиреЛрдВ рдХреЛ рдШрдВрдЯреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВ"
+ },
+ "convertHoursToDays": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "decimalPlaces": "рджрд╢рдорд▓рд╡ рд╕реНрдерд╛рди",
+ "description": "рдШрдВрдЯреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рджрд┐рдиреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рдШрдВрдЯреЗ",
+ "placesPlaceholder": "рд╕реНрдерд╛рди",
+ "resultTitle": "рджрд┐рди",
+ "showBreakdown": "рд╡рд┐рд╕реНрддреГрдд рд╡рд┐рд╡рд░рдг рджрд┐рдЦрд╛рдПрдВ",
+ "title": "рдШрдВрдЯреЛрдВ рдХреЛ рджрд┐рдиреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВ"
+ },
+ "convertSecondsToTime": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "рд╕реЗрдХрдВрдб рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдкрдардиреАрдп рд╕рдордп рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "formatDHMS": "рджрд┐рди:рдШрдВрдЯреЗ:рдорд┐рдирдЯ:рд╕реЗрдХрдВрдб",
+ "formatHMS": "рдШрдВрдЯреЗ:рдорд┐рдирдЯ:рд╕реЗрдХрдВрдб",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕реЗрдХрдВрдб",
+ "resultTitle": "рд╕рдордп",
+ "showZeroValues": "рд╢реВрдиреНрдп рдорд╛рди рджрд┐рдЦрд╛рдПрдВ",
+ "timeFormat": "рд╕рдордп рдкреНрд░рд╛рд░реВрдк",
+ "title": "рд╕реЗрдХрдВрдб рдХреЛ рд╕рдордп рдореЗрдВ рдмрджрд▓реЗрдВ"
+ },
+ "convertTimeToSeconds": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "рд╕рдордп рдкреНрд░рд╛рд░реВрдк рдХреЛ рд╕реЗрдХрдВрдб рдХреА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "formatDHMS": "рджрд┐рди:рдШрдВрдЯреЗ:рдорд┐рдирдЯ:рд╕реЗрдХрдВрдб",
+ "formatHMS": "рдШрдВрдЯреЗ:рдорд┐рдирдЯ:рд╕реЗрдХрдВрдб",
+ "inputPlaceholder": "рдЬреИрд╕реЗ 1:30:45 рдпрд╛ 1d 2h 30m 45s",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕рдордп",
+ "resultTitle": "рд╕реЗрдХрдВрдб",
+ "timeFormat": "рд╕рдордп рдкреНрд░рд╛рд░реВрдк",
+ "title": "рд╕рдордп рдХреЛ рд╕реЗрдХрдВрдб рдореЗрдВ рдмрджрд▓реЗрдВ"
+ },
+ "crontabGuru": {
+ "countPlaceholder": "рд╕рдВрдЦреНрдпрд╛",
+ "cronOptions": "Cron рд╡рд┐рдХрд▓реНрдк",
+ "description": "Cron рдПрдХреНрд╕рдкреНрд░реЗрд╢рди рдХреЛ рдорд╛рдирд╡-рдкрдардиреАрдп рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "expressionPlaceholder": "рдЬреИрд╕реЗ */5 * * * *",
+ "inputTitle": "рдЗрдирдкреБрдЯ Cron рдПрдХреНрд╕рдкреНрд░реЗрд╢рди",
+ "resultTitle": "рдорд╛рдирд╡-рдкрдардиреАрдп рд╡рд┐рд╡рд░рдг",
+ "runCount": "рд░рди рдХреА рд╕рдВрдЦреНрдпрд╛",
+ "showNextRuns": "рдЕрдЧрд▓реЗ рд░рди рджрд┐рдЦрд╛рдПрдВ",
+ "title": "Crontab рдЧреБрд░реБ"
+ },
+ "timeBetweenDates": {
+ "dateOptions": "рддрд┐рдерд┐ рд╡рд┐рдХрд▓реНрдк",
+ "description": "рджреЛ рддрд┐рдерд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рдХрд╛ рд╕рдордп рдЕрдВрддрд░рд╛рд▓ рдЬреНрдЮрд╛рдд рдХрд░реЗрдВред",
+ "endDate": "рдЕрдВрддрд┐рдо рддрд┐рдерд┐",
+ "endDatePlaceholder": "YYYY-MM-DD",
+ "endTime": "рдЕрдВрддрд┐рдо рд╕рдордп",
+ "endTimePlaceholder": "HH:MM:SS",
+ "formatDays": "рджрд┐рди",
+ "formatHours": "рдШрдВрдЯреЗ",
+ "formatMinutes": "рдорд┐рдирдЯ",
+ "formatSeconds": "рд╕реЗрдХрдВрдб",
+ "includeTime": "рд╕рдордп рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ",
+ "inputTitle": "рддрд┐рдерд┐ рдЬреЛрдбрд╝реЗ",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "resultTitle": "рд╕рдордп рдЕрдВрддрд░рд╛рд▓",
+ "startDate": "рд╢реБрд░реБрдЖрддреА рддрд┐рдерд┐",
+ "startDatePlaceholder": "YYYY-MM-DD",
+ "startTime": "рд╢реБрд░реБрдЖрддреА рд╕рдордп",
+ "startTimePlaceholder": "HH:MM:SS",
+ "title": "рддрд┐рдерд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рд╕рдордп"
+ },
+ "truncateClockTime": {
+ "description": "рд╕рдордп рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реНрддрд░ рддрдХ рдХрд╛рдЯреЗрдВред",
+ "format12Hour": "12 рдШрдВрдЯреЗ рдкреНрд░рд╛рд░реВрдк",
+ "format24Hour": "24 рдШрдВрдЯреЗ рдкреНрд░рд╛рд░реВрдк",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╕рдордп",
+ "resultTitle": "рдХрд╛рдЯрд╛ рдЧрдпрд╛ рд╕рдордп",
+ "roundDown": "рдиреАрдЪреЗ рдЧреЛрд▓ рдХрд░реЗрдВ",
+ "roundUp": "рдКрдкрд░ рдЧреЛрд▓ рдХрд░реЗрдВ",
+ "timeFormat": "рд╕рдордп рдкреНрд░рд╛рд░реВрдк",
+ "title": "рдШрдбрд╝реА рдХрд╛ рд╕рдордп рдХрд╛рдЯреЗрдВ",
+ "truncateTo": "рдХрд╛рдЯрдиреЗ рдХрд╛ рд╕реНрддрд░",
+ "truncateToHours": "рдШрдВрдЯреЗ",
+ "truncateToMinutes": "рдорд┐рдирдЯ",
+ "truncateToSeconds": "рд╕реЗрдХрдВрдб",
+ "truncationOptions": "рдХрд╛рдЯрдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк"
+ }
+}
diff --git a/public/locales/hi/translation.json b/public/locales/hi/translation.json
new file mode 100644
index 0000000..3fdf9ba
--- /dev/null
+++ b/public/locales/hi/translation.json
@@ -0,0 +1,254 @@
+{
+ "app": {
+ "language": "рднрд╛рд╖рд╛",
+ "title": "рдУрдордиреА рдЯреВрд▓реНрд╕"
+ },
+ "audio": {
+ "changeSpeed": {
+ "description": "рдСрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдкреНрд▓реЗрдмреИрдХ рдЧрддрд┐ рдмрджрд▓реЗрдВред рдкрд┐рдЪ рдмрдирд╛рдП рд░рдЦрддреЗ рд╣реБрдП рдСрдбрд┐рдпреЛ рдХреЛ рддреЗрдЬрд╝ рдпрд╛ рдзреАрдорд╛ рдХрд░реЗрдВред",
+ "name": "рдСрдбрд┐рдпреЛ рдЧрддрд┐ рдмрджрд▓реЗрдВ",
+ "shortDescription": "рдСрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдЧрддрд┐ рдмрджрд▓реЗрдВ"
+ },
+ "extractAudio": {
+ "description": "рд╡реАрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдСрдбрд┐рдпреЛ рдЯреНрд░реИрдХ рдирд┐рдХрд╛рд▓реЗрдВ рдФрд░ рдЗрд╕реЗ рдЕрдкрдиреЗ рдЪреБрдиреЗ рд╣реБрдП рдкреНрд░рд╛рд░реВрдк (рдПрдПрд╕реА, рдПрдордкреА3, рдбрдмреНрд▓реНрдпреВрдПрд╡реА) рдореЗрдВ рдПрдХ рдЕрд▓рдЧ рдСрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рд╣реЗрдЬреЗрдВред",
+ "name": "рдСрдбрд┐рдпреЛ рдирд┐рдХрд╛рд▓реЗрдВ",
+ "shortDescription": "рд╡реАрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓реЛрдВ (рдПрдордкреА4, рдПрдордУрд╡реА, рдЖрджрд┐) рд╕реЗ рдСрдбрд┐рдпреЛ рдирд┐рдХрд╛рд▓реЗрдВ рдПрдПрд╕реА, рдПрдордкреА3, рдпрд╛ рдбрдмреНрд▓реНрдпреВрдПрд╡реА рдореЗрдВред"
+ }
+ },
+ "baseFileInput": {
+ "copyFailed": "рдХреЙрдкреА рдХрд░рдиреЗ рдореЗрдВ рд╡рд┐рдлрд▓: {{error}}",
+ "dropFileHere": "рдпрд╣рд╛рдБ рдЕрдкрдиреА {{type}} рдбрд╛рд▓реЗрдВ",
+ "fileCopied": "рдлрд╝рд╛рдЗрд▓ рдХреЙрдкреА рдХреА рдЧрдИ",
+ "selectFileDescription": "рдпрд╣рд╛рдБ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ рдЕрдкрдиреЗ рдбрд┐рд╡рд╛рдЗрд╕ рд╕реЗ {{type}} рдЪреБрдирдиреЗ рдХреЗ рд▓рд┐рдП, Ctrl+V рджрдмрд╛рдПрдВ рдХреНрд▓рд┐рдкрдмреЛрд░реНрдб рд╕реЗ {{type}} рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдпрд╛ рдбреЗрд╕реНрдХрдЯреЙрдк рд╕реЗ рдлрд╝рд╛рдЗрд▓ рдХреЛ рдЦреАрдВрдЪрдХрд░ рдбрд╛рд▓реЗрдВ"
+ },
+ "categories": {
+ "audio": {
+ "description": "рдСрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ рд╡реАрдбрд┐рдпреЛ рд╕реЗ рдСрдбрд┐рдпреЛ рдирд┐рдХрд╛рд▓реЗрдВ, рдСрдбрд┐рдпреЛ рдЧрддрд┐ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░реЗрдВ, рдХрдИ рдСрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдорд░реНрдЬ рдХрд░реЗрдВ рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "рдСрдбрд┐рдпреЛ рдЯреВрд▓реНрд╕"
+ },
+ "csv": {
+ "description": "CSV рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ - CSV рдХреЛ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рд╛рд░реВрдкреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВ, CSV рдбреЗрдЯрд╛ рдореЗрдВ рд╣реЗрд░рдлреЗрд░ рдХрд░реЗрдВ, CSV рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдорд╛рдиреНрдп рдХрд░реЗрдВ, рдФрд░ CSV рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдХреБрд╢рд▓рддрд╛рдкреВрд░реНрд╡рдХ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░реЗрдВред",
+ "title": "CSV рдЯреВрд▓реНрд╕"
+ },
+ "gif": {
+ "description": "GIF рдПрдирд┐рдореЗрд╢рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ рдкрд╛рд░рджрд░реНрд╢реА GIF рдмрдирд╛рдПрдВ, GIF рдлреНрд░реЗрдо рдирд┐рдХрд╛рд▓реЗрдВ, GIF рдореЗрдВ рдЯреЗрдХреНрд╕реНрдЯ рдЬреЛрдбрд╝реЗрдВ, рдХреНрд░реЙрдк, рдШреБрдорд╛рдПрдВ, GIF рдХреЛ рдЙрд▓рдЯрд╛ рдХрд░реЗрдВ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "GIF рдЯреВрд▓реНрд╕"
+ },
+ "image-generic": {
+ "description": "рдЪрд┐рддреНрд░реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ рд╕рдВрдкреАрдбрд╝рд┐рдд рдХрд░реЗрдВ, рдЖрдХрд╛рд░ рдмрджрд▓реЗрдВ, рдХреНрд░реЙрдк рдХрд░реЗрдВ, JPG рдореЗрдВ рдмрджрд▓реЗрдВ, рдШреБрдорд╛рдПрдВ, рдкреГрд╖реНрдарднреВрдорд┐ рд╣рдЯрд╛рдПрдВ рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "рдЫрд╡рд┐ рдЯреВрд▓реНрд╕"
+ },
+ "json": {
+ "description": "JSON рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ JSON рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд╕реБрдВрджрд░ рдФрд░ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдХрд░реЗрдВ, JSON рд╕рд░рдгрд┐рдпреЛрдВ рдХреЛ рд╕рдорддрд▓ рдХрд░реЗрдВ, JSON рдореВрд▓реНрдпреЛрдВ рдХреЛ рд╕реНрдЯреНрд░рд┐рдВрдЧрд┐рдлрд╛рдИ рдХрд░реЗрдВ, рдбреЗрдЯрд╛ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫ",
+ "title": "JSON рдЯреВрд▓реНрд╕"
+ },
+ "list": {
+ "description": "рд╕реВрдЪрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ, рдЙрд▓рдЯрд╛ рдХрд░реЗрдВ, рд╕реВрдЪрд┐рдпреЛрдВ рдХреЛ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдХрд░реЗрдВ, рдЕрджреНрд╡рд┐рддреАрдп рдФрд░ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рд╕реВрдЪреА рдЖрдЗрдЯрдо рдЦреЛрдЬреЗрдВ, рд╕реВрдЪреА рдЖрдЗрдЯрдо рд╡рд┐рднрд╛рдЬрдХ рдмрджрд▓реЗрдВ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "рд╕реВрдЪреА рдЯреВрд▓реНрд╕"
+ },
+ "number": {
+ "description": "рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ рд╕рдВрдЦреНрдпрд╛ рдЕрдиреБрдХреНрд░рдо рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВ, рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рд╢рдмреНрджреЛрдВ рдореЗрдВ рдФрд░ рд╢рдмреНрджреЛрдВ рдХреЛ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдореЗрдВ рдмрджрд▓реЗрдВ, рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ, рдЧреЛрд▓ рдХрд░реЗрдВ, рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХрд╛ рдЧреБрдгрдирдЦрдВрдб рдХрд░реЗрдВ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "рд╕рдВрдЦреНрдпрд╛ рдЯреВрд▓реНрд╕"
+ },
+ "pdf": {
+ "description": "PDF рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ - PDF рд╕реЗ рдЯреЗрдХреНрд╕реНрдЯ рдирд┐рдХрд╛рд▓реЗрдВ, PDF рдХреЛ рдЕрдиреНрдп рдкреНрд░рд╛рд░реВрдкреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВ, PDF рдореЗрдВ рд╣реЗрд░рдлреЗрд░ рдХрд░реЗрдВ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "PDF рдЯреВрд▓реНрд╕"
+ },
+ "png": {
+ "description": "PNG рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ PNG рдХреЛ JPG рдореЗрдВ рдмрджрд▓реЗрдВ, рдкрд╛рд░рджрд░реНрд╢реА PNG рдмрдирд╛рдПрдВ, PNG рд░рдВрдЧ рдмрджрд▓реЗрдВ, рдХреНрд░реЙрдк, рдШреБрдорд╛рдПрдВ, PNG рдХрд╛ рдЖрдХрд╛рд░ рдмрджрд▓реЗрдВ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "PNG рдЯреВрд▓реНрд╕"
+ },
+ "seeAll": "рд╕рднреА {{title}} рджреЗрдЦреЗрдВ",
+ "string": {
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдЫрд╡рд┐рдпреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВ, рдЯреЗрдХреНрд╕реНрдЯ рдЦреЛрдЬреЗрдВ рдФрд░ рдмрджрд▓реЗрдВ, рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдЯреБрдХрдбрд╝реЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ, рдЯреЗрдХреНрд╕реНрдЯ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝реЗрдВ, рдЯреЗрдХреНрд╕реНрдЯ рджреЛрд╣рд░рд╛рдПрдВ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "рдЯреЗрдХреНрд╕реНрдЯ рдЯреВрд▓реНрд╕"
+ },
+ "time": {
+ "description": "рд╕рдордп рдФрд░ рддрд┐рдерд┐ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ рд╕рдордп рдЕрдВрддрд░ рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдВ, рд╕рдордп рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рдмреАрдЪ рдмрджрд▓реЗрдВ, рддрд┐рдерд┐рдпреЛрдВ рдХреЛ рдлреЙрд░реНрдореЗрдЯ рдХрд░реЗрдВ, рддрд┐рдерд┐ рдЕрдиреБрдХреНрд░рдо рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "рд╕рдордп рдЯреВрд▓реНрд╕"
+ },
+ "try": "{{title}} рдЖрдЬрд╝рдорд╛рдПрдВ",
+ "video": {
+ "description": "рд╡реАрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ тАУ рд╡реАрдбрд┐рдпреЛ рд╕реЗ рдлреНрд░реЗрдо рдирд┐рдХрд╛рд▓реЗрдВ, рд╡реАрдбрд┐рдпреЛ рд╕реЗ GIF рдмрдирд╛рдПрдВ, рд╡реАрдбрд┐рдпреЛ рдХреЛ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рд╛рд░реВрдкреЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫред",
+ "title": "рд╡реАрдбрд┐рдпреЛ рдЯреВрд▓реНрд╕"
+ },
+ "xml": {
+ "description": "XML рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреВрд▓реНрд╕ - рд╡реНрдпреВрдЕрд░, рдмреНрдпреВрдЯрд┐рдлрд╛рдпрд░, рд╡реИрд▓рд┐рдбреЗрдЯрд░ рдФрд░ рдмрд╣реБрдд рдХреБрдЫ",
+ "title": "XML рдЯреВрд▓реНрд╕"
+ }
+ },
+ "csv": {
+ "findIncompleteCsvRecords": {
+ "description": "рдмрд╕ рдиреАрдЪреЗ рдлреЙрд░реНрдо рдореЗрдВ рдЕрдкрдиреА рд╕реАрдПрд╕рд╡реА рдлрд╝рд╛рдЗрд▓ рдЕрдкрд▓реЛрдб рдХрд░реЗрдВ рдФрд░ рдпрд╣ рдЯреВрд▓ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЬрд╛рдВрдЪ рдХрд░реЗрдЧрд╛ рдХрд┐ рдХреНрдпрд╛ рдХреЛрдИ рдкрдВрдХреНрддрд┐ рдпрд╛ рд╕реНрддрдВрдн рдореВрд▓реНрдп рдирд╣реАрдВ рдЦреЛ рд░рд╣реЗ рд╣реИрдВред рдЯреВрд▓ рд╡рд┐рдХрд▓реНрдкреЛрдВ рдореЗрдВ, рдЖрдк рдЗрдирдкреБрдЯ рдлрд╝рд╛рдЗрд▓ рдкреНрд░рд╛рд░реВрдк рдХреЛ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рд╡рд┐рднрд╛рдЬрдХ, рдЙрджреНрдзрд░рдг рд╡рд░реНрдг, рдФрд░ рдЯрд┐рдкреНрдкрдгреА рд╡рд░реНрдг рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ)ред рдЗрд╕рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд, рдЖрдк рдЦрд╛рд▓реА рдореВрд▓реНрдпреЛрдВ рдХреА рдЬрд╛рдВрдЪ рд╕рдХреНрд╖рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЦрд╛рд▓реА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЫреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдЖрдЙрдЯрдкреБрдЯ рдореЗрдВ рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдкрд░ рд╕реАрдорд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред",
+ "name": "рдЕрдзреВрд░реЗ рд╕реАрдПрд╕рд╡реА рд░рд┐рдХреЙрд░реНрдб рдЦреЛрдЬреЗрдВ",
+ "shortDescription": "рд╕реАрдПрд╕рд╡реА рдореЗрдВ рдЬрд▓реНрджреА рд╕реЗ рдкрдВрдХреНрддрд┐рдпрд╛рдВ рдФрд░ рд╕реНрддрдВрдн рдЦреЛрдЬреЗрдВ рдЬреЛ рдореВрд▓реНрдп рдЦреЛ рд░рд╣реЗ рд╣реИрдВред"
+ }
+ },
+ "hero": {
+ "brand": "рдУрдордиреАрдЯреВрд▓реНрд╕",
+ "description": "рдУрдордиреАрдЯреВрд▓реНрд╕ рдХреЗ рд╕рд╛рде рдЕрдкрдиреА рдЙрддреНрдкрд╛рджрдХрддрд╛ рдмрдврд╝рд╛рдПрдВ, рдЬрд▓реНрджреА рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдВрддрд┐рдо рдЯреВрд▓рдХрд┐рдЯ! рдЫрд╡рд┐рдпреЛрдВ, рдЯреЗрдХреНрд╕реНрдЯ, рд╕реВрдЪрд┐рдпреЛрдВ рдФрд░ рдбреЗрдЯрд╛ рдХреЛ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдЬрд╛рд░реЛрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛-рдЕрдиреБрдХреВрд▓ рдЙрдкрдпреЛрдЧрд┐рддрд╛рдУрдВ рддрдХ рдкрд╣реБрдВрдЪреЗрдВ, рд╕рднреА рд╕реАрдзреЗ рдЕрдкрдиреЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕реЗред",
+ "examples": {
+ "calculateNumberSum": "рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХрд╛ рдпреЛрдЧ рдХрд░реЗрдВ",
+ "changeGifSpeed": "GIF рдЧрддрд┐ рдмрджрд▓реЗрдВ",
+ "compressPng": "PNG рд╕рдВрдкреАрдбрд╝рд┐рдд рдХрд░реЗрдВ",
+ "createTransparentImage": "рдкрд╛рд░рджрд░реНрд╢реА рдЫрд╡рд┐ рдмрдирд╛рдПрдВ",
+ "prettifyJson": "JSON рд╕реБрдВрджрд░ рдмрдирд╛рдПрдВ",
+ "sortList": "рд╕реВрдЪреА рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ",
+ "splitPdf": "PDF рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ",
+ "splitText": "рдЯреЗрдХреНрд╕реНрдЯ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ",
+ "trimVideo": "рд╡реАрдбрд┐рдпреЛ рдЯреНрд░рд┐рдо рдХрд░реЗрдВ"
+ },
+ "searchPlaceholder": "рд╕рднреА рдЯреВрд▓реНрд╕ рдЦреЛрдЬреЗрдВ",
+ "title": "рдХреЗ рд╕рд╛рде рдЬрд▓реНрджреА рдХрд╛рдо рдХрд░реЗрдВ"
+ },
+ "inputFooter": {
+ "clear": "рд╕рд╛рдлрд╝ рдХрд░реЗрдВ",
+ "copyToClipboard": "рдХреНрд▓рд┐рдкрдмреЛрд░реНрдб рдкрд░ рдХреЙрдкреА рдХрд░реЗрдВ",
+ "importFromFile": "рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдЖрдпрд╛рдд рдХрд░реЗрдВ"
+ },
+ "list": {
+ "group": {
+ "description": "рд╕реВрдЪреА рдЖрдЗрдЯрдо рдХреЛ рд╕рдореВрд╣рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рджреБрдирд┐рдпрд╛ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдЙрдкрдпреЛрдЧрд┐рддрд╛ред рдЕрдкрдиреА рд╕реВрдЪреА рдЗрдирдкреБрдЯ рдХрд░реЗрдВ рдФрд░ рд╕рдореВрд╣реАрдХрд░рдг рдорд╛рдирджрдВрдб рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ рддрд╛рдХрд┐ рдЖрдЗрдЯрдо рдХреЛ рддрд╛рд░реНрдХрд┐рдХ рд╕рдореВрд╣реЛрдВ рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред рдбреЗрдЯрд╛ рдХреЛ рд╡рд░реНрдЧреАрдХреГрдд рдХрд░рдиреЗ, рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ, рдпрд╛ рд╕рдВрд░рдЪрд┐рдд рд╕реВрдЪрд┐рдпрд╛рдВ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд┐рд▓реНрдХреБрд▓ рд╕рд╣реАред рдХрд╕реНрдЯрдо рд╡рд┐рднрд╛рдЬрдХ рдФрд░ рд╡рд┐рднрд┐рдиреНрди рд╕рдореВрд╣реАрдХрд░рдг рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред",
+ "name": "рд╕рдореВрд╣",
+ "shortDescription": "рд╕рд╛рдорд╛рдиреНрдп рдЧреБрдгреЛрдВ рджреНрд╡рд╛рд░рд╛ рд╕реВрдЪреА рдЖрдЗрдЯрдо рдХреЛ рд╕рдореВрд╣рд┐рдд рдХрд░реЗрдВ"
+ },
+ "reverse": {
+ "description": "рдпрд╣ рдПрдХ рд╕реБрдкрд░ рд╕рд░рд▓ рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реИ рдЬреЛ рд╕рднреА рд╕реВрдЪреА рдЖрдЗрдЯрдо рдХреЛ рдЙрд▓реНрдЯреЗ рдХреНрд░рдо рдореЗрдВ рдкреНрд░рд┐рдВрдЯ рдХрд░рддреА рд╣реИред рдЗрдирдкреБрдЯ рдЖрдЗрдЯрдо рдХрд┐рд╕реА рднреА рдкреНрд░рддреАрдХ рд╕реЗ рдЕрд▓рдЧ рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЖрдк рдЙрд▓рдЯреЗ рд╕реВрдЪреА рдЖрдЗрдЯрдо рдХреЗ рд╡рд┐рднрд╛рдЬрдХ рдХреЛ рднреА рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред",
+ "name": "рдЙрд▓рдЯрд╛",
+ "shortDescription": "рдЬрд▓реНрджреА рд╕реЗ рд╕реВрдЪреА рдХреЛ рдЙрд▓рдЯрд╛ рдХрд░реЗрдВ"
+ },
+ "sort": {
+ "description": "рдпрд╣ рдПрдХ рд╕реБрдкрд░ рд╕рд░рд▓ рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реИ рдЬреЛ рд╕реВрдЪреА рдореЗрдВ рдЖрдЗрдЯрдо рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░рддреА рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдмрдврд╝рддреЗ рдпрд╛ рдШрдЯрддреЗ рдХреНрд░рдо рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рддреА рд╣реИред рдЖрдк рдЖрдЗрдЯрдо рдХреЛ рд╡рд░реНрдгрд╛рдиреБрдХреНрд░рдорд┐рдХ, рд╕рдВрдЦреНрдпрд╛рддреНрдордХ, рдпрд╛ рдЙрдирдХреА рд▓рдВрдмрд╛рдИ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдХреНрд░рдордмрджреНрдз рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдк рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдФрд░ рдЦрд╛рд▓реА рдЖрдЗрдЯрдо рдХреЛ рднреА рд╣рдЯрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд╕рд╛рде рд╣реА рдЙрди рдЖрдЗрдЯрдо рдХреЛ рдЯреНрд░рд┐рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рдирдХреЗ рдЪрд╛рд░реЛрдВ рдУрд░ рд╕рдлреЗрдж рд╕реНрдерд╛рди рд╣реИред рдЖрдк рдЗрдирдкреБрдЯ рд╕реВрдЪреА рдЖрдЗрдЯрдо рдХреЛ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рднреА рд╡рд┐рднрд╛рдЬрдХ рд╡рд░реНрдг рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдк рд╕реЗ рдЙрдиреНрд╣реЗрдВ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд, рдЖрдк рдХреНрд░рдордмрджреНрдз рдЖрдЙрдЯрдкреБрдЯ рд╕реВрдЪреА рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдбрд┐рд▓рд┐рдорд┐рдЯрд░ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред",
+ "name": "рдХреНрд░рдордмрджреНрдз",
+ "shortDescription": "рдЬрд▓реНрджреА рд╕реЗ рд╕реВрдЪреА рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ"
+ }
+ },
+ "navbar": {
+ "buyMeACoffee": "рдореБрдЭреЗ рдХреЙрдлреА рдЦрд░реАрджреЗрдВ",
+ "home": "рд╣реЛрдо",
+ "tools": "рдЯреВрд▓реНрд╕"
+ },
+ "number": {
+ "generate": {
+ "description": "рдЕрдкрдиреЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдкреВрд░реНрдгрд╛рдВрдХреЛрдВ рдХреА рд╕реВрдЪреА рдХреА рддреБрд░рдВрдд рдЧрдгрдирд╛ рдХрд░реЗрдВред рдЕрдкрдиреА рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╕ рдкрд╣рд▓рд╛ рдкреВрд░реНрдгрд╛рдВрдХ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ, рдиреАрдЪреЗ рд╡рд┐рдХрд▓реНрдкреЛрдВ рдореЗрдВ рдорд╛рди рдФрд░ рдХреБрд▓ рд╕рдВрдЦреНрдпрд╛ рдмрджрд▓реЗрдВ, рдФрд░ рдпрд╣ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдЙрддрдиреЗ рдкреВрд░реНрдгрд╛рдВрдХ рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧреА",
+ "name": "рд╕рдВрдЦреНрдпрд╛рдПрдВ рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВ",
+ "shortDescription": "рдЕрдкрдиреЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдкреВрд░реНрдгрд╛рдВрдХреЛрдВ рдХреА рд╕реВрдЪреА рдХреА рддреБрд░рдВрдд рдЧрдгрдирд╛ рдХрд░реЗрдВ"
+ },
+ "sum": {
+ "description": "рдпрд╣ рдПрдХ рд╕реБрдкрд░ рд╕рд░рд▓ рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реИ рдЬреЛ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рдЬреЛрдбрд╝рддреА рд╣реИред рдЗрдирдкреБрдЯ рд╕рдВрдЦреНрдпрд╛рдПрдВ рдХрд┐рд╕реА рднреА рдкреНрд░рддреАрдХ рд╕реЗ рдЕрд▓рдЧ рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИрдВ рдФрд░ рдЖрдк рдЬреЛрдбрд╝реА рдЧрдИ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЗ рд╡рд┐рднрд╛рдЬрдХ рдХреЛ рднреА рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред",
+ "name": "рд╕рдВрдЦреНрдпрд╛рдПрдВ рдЬреЛрдбрд╝реЗрдВ",
+ "shortDescription": "рдЬрд▓реНрджреА рд╕реЗ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреА рд╕реВрдЪреА рдЬреЛрдбрд╝реЗрдВ"
+ }
+ },
+ "numericInputWithUnit": {
+ "unit": "рдЗрдХрд╛рдИ"
+ },
+ "pdf": {
+ "compressPdf": {
+ "description": "рдЧреЛрд╕реНрдЯрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЧреБрдгрд╡рддреНрддрд╛ рдмрдирд╛рдП рд░рдЦрддреЗ рд╣реБрдП рдкреАрдбреАрдПрдл рдлрд╝рд╛рдЗрд▓ рдЖрдХрд╛рд░ рдХрдо рдХрд░реЗрдВ",
+ "name": "рдкреАрдбреАрдПрдл рд╕рдВрдкреАрдбрд╝рд┐рдд рдХрд░реЗрдВ",
+ "shortDescription": "рдЕрдкрдиреЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рдкреАрдбреАрдПрдл рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рд╕рдВрдкреАрдбрд╝рд┐рдд рдХрд░реЗрдВ"
+ },
+ "mergePdf": {
+ "description": "рдХрдИ рдкреАрдбреАрдПрдл рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдПрдХ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред",
+ "name": "рдкреАрдбреАрдПрдл рдорд░реНрдЬ рдХрд░реЗрдВ",
+ "shortDescription": "рдХрдИ рдкреАрдбреАрдПрдл рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдПрдХ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдореЗрдВ рдорд░реНрдЬ рдХрд░реЗрдВ"
+ },
+ "pdfToEpub": {
+ "description": "рдмреЗрд╣рддрд░ рдИ-рд░реАрдбрд░ рд╕рдВрдЧрддрддрд╛ рдХреЗ рд▓рд┐рдП рдкреАрдбреАрдПрдл рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдХреЛ рдИрдкреАрдпреВрдмреА рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "name": "рдкреАрдбреАрдПрдл рд╕реЗ рдИрдкреАрдпреВрдмреА",
+ "shortDescription": "рдкреАрдбреАрдПрдл рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдИрдкреАрдпреВрдмреА рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВ"
+ },
+ "protectPdf": {
+ "description": "рдЕрдкрдиреЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рдЕрдкрдиреА рдкреАрдбреАрдПрдл рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдкрд╛рд╕рд╡рд░реНрдб рд╕реБрд░рдХреНрд╖рд╛ рдЬреЛрдбрд╝реЗрдВ",
+ "name": "рдкреАрдбреАрдПрдл рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "shortDescription": "рдкреАрдбреАрдПрдл рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рдкрд╛рд╕рд╡рд░реНрдб рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ"
+ },
+ "splitPdf": {
+ "description": "рдкреЗрдЬ рдирдВрдмрд░ рдпрд╛ рд╢реНрд░реЗрдгрд┐рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреАрдбреАрдПрдл рдлрд╝рд╛рдЗрд▓ рд╕реЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреЗрдЬ рдирд┐рдХрд╛рд▓реЗрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, 1,5-8)",
+ "name": "рдкреАрдбреАрдПрдл рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ",
+ "shortDescription": "рдкреАрдбреАрдПрдл рдлрд╝рд╛рдЗрд▓ рд╕реЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреЗрдЬ рдирд┐рдХрд╛рд▓реЗрдВ"
+ }
+ },
+ "resultFooter": {
+ "copy": "рдХреНрд▓рд┐рдкрдмреЛрд░реНрдб рдкрд░ рдХреЙрдкреА рдХрд░реЗрдВ",
+ "download": "рдбрд╛рдЙрдирд▓реЛрдб"
+ },
+ "string": {
+ "createPalindrome": {
+ "description": "рдХрд┐рд╕реА рднреА рдЯреЗрдХреНрд╕реНрдЯ рд╕реЗ рдкреИрд▓рд┐рдВрдбреНрд░реЛрдо рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рджреБрдирд┐рдпрд╛ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдЙрдкрдпреЛрдЧрд┐рддрд╛ред рдЯреЗрдХреНрд╕реНрдЯ рдЗрдирдкреБрдЯ рдХрд░реЗрдВ рдФрд░ рдЗрд╕реЗ рддреБрд░рдВрдд рдПрдХ рдкреИрд▓рд┐рдВрдбреНрд░реЛрдо рдореЗрдВ рдмрджрд▓ рджреЗрдВ рдЬреЛ рдЖрдЧреЗ рдФрд░ рдкреАрдЫреЗ рдПрдХ рдЬреИрд╕рд╛ рдкрдврд╝рддрд╛ рд╣реИред рд╢рдмреНрдж рдЦреЗрд▓реЛрдВ, рд╕рдордорд┐рдд рдЯреЗрдХреНрд╕реНрдЯ рдкреИрдЯрд░реНрди рдмрдирд╛рдиреЗ, рдпрд╛ рднрд╛рд╖рд╛рдИ рдЬрд┐рдЬреНрдЮрд╛рд╕рд╛рдУрдВ рдХреА рдЦреЛрдЬ рдХреЗ рд▓рд┐рдП рдмрд┐рд▓реНрдХреБрд▓ рд╕рд╣реАред",
+ "name": "рдкреИрд▓рд┐рдВрдбреНрд░реЛрдо рдмрдирд╛рдПрдВ",
+ "shortDescription": "рдРрд╕рд╛ рдЯреЗрдХреНрд╕реНрдЯ рдмрдирд╛рдПрдВ рдЬреЛ рдЖрдЧреЗ рдФрд░ рдкреАрдЫреЗ рдПрдХ рдЬреИрд╕рд╛ рдкрдврд╝рддрд╛ рд╣реИ"
+ },
+ "palindrome": {
+ "description": "рдпрд╣ рдЬрд╛рдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рджреБрдирд┐рдпрд╛ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХрд┐ рдЯреЗрдХреНрд╕реНрдЯ рдкреИрд▓рд┐рдВрдбреНрд░реЛрдо рд╣реИ рдпрд╛ рдирд╣реАрдВред рддреБрд░рдВрдд рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдХреНрдпрд╛ рдЖрдкрдХрд╛ рдЯреЗрдХреНрд╕реНрдЯ рдЖрдЧреЗ рдФрд░ рдкреАрдЫреЗ рдПрдХ рдЬреИрд╕рд╛ рдкрдврд╝рддрд╛ рд╣реИред рд╢рдмреНрдж рдкрд╣реЗрд▓рд┐рдпреЛрдВ, рднрд╛рд╖рд╛рдИ рд╡рд┐рд╢реНрд▓реЗрд╖рдг, рдпрд╛ рд╕рдордорд┐рдд рдЯреЗрдХреНрд╕реНрдЯ рдкреИрдЯрд░реНрди рдХреЛ рдорд╛рдиреНрдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд┐рд▓реНрдХреБрд▓ рд╕рд╣реАред рд╡рд┐рднрд┐рдиреНрди рд╡рд┐рднрд╛рдЬрдХреЛрдВ рдФрд░ рдмрд╣реБ-рд╢рдмреНрдж рдкреИрд▓рд┐рдВрдбреНрд░реЛрдо рдкрд╣рдЪрд╛рди рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред",
+ "name": "рдкреИрд▓рд┐рдВрдбреНрд░реЛрдо",
+ "shortDescription": "рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ рдХреНрдпрд╛ рдЯреЗрдХреНрд╕реНрдЯ рдЖрдЧреЗ рдФрд░ рдкреАрдЫреЗ рдПрдХ рдЬреИрд╕рд╛ рдкрдврд╝рддрд╛ рд╣реИ"
+ },
+ "repeat": {
+ "description": "рдпрд╣ рдЯреВрд▓ рдЖрдкрдХреЛ рд╡реИрдХрд▓реНрдкрд┐рдХ рд╡рд┐рднрд╛рдЬрдХ рдХреЗ рд╕рд╛рде рджрд┐рдП рдЧрдП рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдХрдИ рдмрд╛рд░ рджреЛрд╣рд░рд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред",
+ "name": "рдЯреЗрдХреНрд╕реНрдЯ рджреЛрд╣рд░рд╛рдПрдВ",
+ "shortDescription": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдХрдИ рдмрд╛рд░ рджреЛрд╣рд░рд╛рдПрдВ"
+ },
+ "reverse": {
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдЙрд▓рдЯрдиреЗ рдХреЗ рд▓рд┐рдП рджреБрдирд┐рдпрд╛ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдЙрдкрдпреЛрдЧрд┐рддрд╛ред рдХреЛрдИ рднреА рдЯреЗрдХреНрд╕реНрдЯ рдЗрдирдкреБрдЯ рдХрд░реЗрдВ рдФрд░ рдЗрд╕реЗ рддреБрд░рдВрдд рдЙрд▓рдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ, рд╡рд░реНрдг рджрд░ рд╡рд░реНрдгред рджрд░реНрдкрдг рдЯреЗрдХреНрд╕реНрдЯ рдмрдирд╛рдиреЗ, рдкреИрд▓рд┐рдВрдбреНрд░реЛрдо рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ, рдпрд╛ рдЯреЗрдХреНрд╕реНрдЯ рдкреИрдЯрд░реНрди рдХреЗ рд╕рд╛рде рдЦреЗрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд┐рд▓реНрдХреБрд▓ рд╕рд╣реАред рдЙрд▓рдЯрддреЗ рд╕рдордп рд╕реНрдерд╛рди рдФрд░ рд╡рд┐рд╢реЗрд╖ рд╡рд░реНрдгреЛрдВ рдХреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред",
+ "name": "рдЙрд▓рдЯрд╛",
+ "shortDescription": "рдХрд┐рд╕реА рднреА рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рд╡рд░реНрдг рджрд░ рд╡рд░реНрдг рдЙрд▓рдЯрд╛ рдХрд░реЗрдВ"
+ },
+ "toMorse": {
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдореЛрд░реНрд╕ рдХреЛрдб рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рджреБрдирд┐рдпрд╛ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдЙрдкрдпреЛрдЧрд┐рддрд╛ред рдмрд╛рдИрдВ рдУрд░ рдЗрдирдкреБрдЯ рдлреЙрд░реНрдо рдореЗрдВ рдЕрдкрдирд╛ рдЯреЗрдХреНрд╕реНрдЯ рд▓реЛрдб рдХрд░реЗрдВ рдФрд░ рдЖрдкрдХреЛ рддреБрд░рдВрдд рдЖрдЙрдЯрдкреБрдЯ рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рдореЛрд░реНрд╕ рдХреЛрдб рдорд┐рд▓реЗрдЧрд╛ред рд╢рдХреНрддрд┐рд╢рд╛рд▓реА, рдореБрдлреНрдд, рдФрд░ рддреЗрдЬрд╝ред рдЯреЗрдХреНрд╕реНрдЯ рд▓реЛрдб рдХрд░реЗрдВ тАУ рдореЛрд░реНрд╕ рдХреЛрдб рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред",
+ "name": "рдЯреЗрдХреНрд╕реНрдЯ рд╕реЗ рдореЛрд░реНрд╕",
+ "shortDescription": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдЬрд▓реНрджреА рд╕реЗ рдореЛрд░реНрд╕ рдореЗрдВ рдПрдирдХреЛрдб рдХрд░реЗрдВ"
+ },
+ "uppercase": {
+ "description": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдмрдбрд╝реЗ рдЕрдХреНрд╖рд░реЛрдВ рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рджреБрдирд┐рдпрд╛ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдмреНрд░рд╛рдЙрдЬрд╝рд░-рдЖрдзрд╛рд░рд┐рдд рдЙрдкрдпреЛрдЧрд┐рддрд╛ред рдмрд╕ рдЕрдкрдирд╛ рдЯреЗрдХреНрд╕реНрдЯ рдЗрдирдкреБрдЯ рдХрд░реЗрдВ рдФрд░ рдпрд╣ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд╕рднреА рдмрдбрд╝реЗ рдЕрдХреНрд╖рд░реЛрдВ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рд╢реАрд░реНрд╖рдХ рдмрдирд╛рдиреЗ, рдЯреЗрдХреНрд╕реНрдЯ рдкрд░ рдЬреЛрд░ рджреЗрдиреЗ, рдпрд╛ рдЯреЗрдХреНрд╕реНрдЯ рдкреНрд░рд╛рд░реВрдк рдХреЛ рдорд╛рдирдХреАрдХреГрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд┐рд▓реНрдХреБрд▓ рд╕рд╣реАред рд╡рд┐рднрд┐рдиреНрди рдЯреЗрдХреНрд╕реНрдЯ рдкреНрд░рд╛рд░реВрдкреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╡рд┐рд╢реЗрд╖ рд╡рд░реНрдгреЛрдВ рдХреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред",
+ "name": "рдмрдбрд╝реЗ рдЕрдХреНрд╖рд░",
+ "shortDescription": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рдмрдбрд╝реЗ рдЕрдХреНрд╖рд░реЛрдВ рдореЗрдВ рдмрджрд▓реЗрдВ"
+ }
+ },
+ "toolExamples": {
+ "subtitle": "рдЖрдЬрд╝рдорд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ!",
+ "title": "{{title}} рдЙрджрд╛рд╣рд░рдг"
+ },
+ "toolFileResult": {
+ "copied": "рдлрд╝рд╛рдЗрд▓ рдХреЙрдкреА рдХреА рдЧрдИ",
+ "copyFailed": "рдХреЙрдкреА рдХрд░рдиреЗ рдореЗрдВ рд╡рд┐рдлрд▓: {{error}}",
+ "loading": "рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ... рдЗрд╕рдореЗрдВ рдХреБрдЫ рд╕рдордп рд▓рдЧ рд╕рдХрддрд╛ рд╣реИред",
+ "result": "рдкрд░рд┐рдгрд╛рдо"
+ },
+ "toolHeader": {
+ "seeExamples": "рдЙрджрд╛рд╣рд░рдг рджреЗрдЦреЗрдВ"
+ },
+ "toolLayout": {
+ "allToolsTitle": "рд╕рднреА {{type}} рдЯреВрд▓реНрд╕"
+ },
+ "toolMultiFileResult": {
+ "copied": "рдлрд╝рд╛рдЗрд▓ рдХреЙрдкреА рдХреА рдЧрдИ",
+ "copyFailed": "рдХреЙрдкреА рдХрд░рдиреЗ рдореЗрдВ рд╡рд┐рдлрд▓: {{error}}",
+ "loading": "рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ... рдЗрд╕рдореЗрдВ рдХреБрдЫ рд╕рдордп рд▓рдЧ рд╕рдХрддрд╛ рд╣реИред",
+ "result": "рдкрд░рд┐рдгрд╛рдо"
+ },
+ "toolMultipleAudioInput": {
+ "inputTitle": "рдЗрдирдкреБрдЯ {{type}}",
+ "noFilesSelected": "рдХреЛрдИ рдлрд╝рд╛рдЗрд▓ рдЪрдпрдирд┐рдд рдирд╣реАрдВ"
+ },
+ "toolMultiplePdfInput": {
+ "inputTitle": "рдЗрдирдкреБрдЯ {{type}}",
+ "noFilesSelected": "рдХреЛрдИ рдлрд╝рд╛рдЗрд▓ рдЪрдпрдирд┐рдд рдирд╣реАрдВ"
+ },
+ "toolOptions": {
+ "title": "рдЯреВрд▓ рд╡рд┐рдХрд▓реНрдк"
+ },
+ "toolTextInput": {
+ "copied": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЙрдкреА рдХрд┐рдпрд╛ рдЧрдпрд╛",
+ "copyFailed": "рдХреЙрдкреА рдХрд░рдиреЗ рдореЗрдВ рд╡рд┐рдлрд▓: {{error}}",
+ "input": "рдЗрдирдкреБрдЯ рдЯреЗрдХреНрд╕реНрдЯ",
+ "placeholder": "рдпрд╣рд╛рдБ рдЕрдкрдирд╛ рдЯреЗрдХреНрд╕реНрдЯ рджрд░реНрдЬ рдХрд░реЗрдВ..."
+ },
+ "toolTextResult": {
+ "copied": "рдЯреЗрдХреНрд╕реНрдЯ рдХреЙрдкреА рдХрд┐рдпрд╛ рдЧрдпрд╛",
+ "copyFailed": "рдХреЙрдкреА рдХрд░рдиреЗ рдореЗрдВ рд╡рд┐рдлрд▓: {{error}}",
+ "loading": "рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ... рдЗрд╕рдореЗрдВ рдХреБрдЫ рд╕рдордп рд▓рдЧ рд╕рдХрддрд╛ рд╣реИред",
+ "result": "рдкрд░рд┐рдгрд╛рдо"
+ }
+}
diff --git a/public/locales/hi/video.json b/public/locales/hi/video.json
new file mode 100644
index 0000000..eff6711
--- /dev/null
+++ b/public/locales/hi/video.json
@@ -0,0 +1,140 @@
+{
+ "changeSpeed": {
+ "description": "рд╡реАрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдкреНрд▓реЗрдмреИрдХ рдЧрддрд┐ рдмрджрд▓реЗрдВред",
+ "factorPlaceholder": "рдХрд╛рд░рдХ (рдЬреИрд╕реЗ 0.5, 1.5, 2.0)",
+ "formatAvi": "AVI",
+ "formatMov": "MOV",
+ "formatMp4": "MP4",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡реАрдбрд┐рдпреЛ",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "preserveAudio": "рдСрдбрд┐рдпреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "resultTitle": "рдЧрддрд┐ рдмрджрд▓реА рдЧрдИ рд╡реАрдбрд┐рдпреЛ",
+ "speedFactor": "рдЧрддрд┐ рдХрд╛рд░рдХ",
+ "speedOptions": "рдЧрддрд┐ рд╡рд┐рдХрд▓реНрдк",
+ "title": "рд╡реАрдбрд┐рдпреЛ рдЧрддрд┐ рдмрджрд▓реЗрдВ"
+ },
+ "compress": {
+ "compressionOptions": "рд╕рдВрдкреАрдбрд╝рди рд╡рд┐рдХрд▓реНрдк",
+ "description": "рд╡реАрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓ рдЖрдХрд╛рд░ рдХрдо рдХрд░реЗрдВред",
+ "formatAvi": "AVI",
+ "formatMp4": "MP4",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡реАрдбрд┐рдпреЛ",
+ "outputFormat": "рдЖрдЙрдЯрдкреБрдЯ рдкреНрд░рд╛рд░реВрдк",
+ "qualityHigh": "рдЙрдЪреНрдЪ",
+ "qualityLow": "рдХрдо",
+ "qualityMedium": "рдордзреНрдпрдо",
+ "resolution": "рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди",
+ "resolution360p": "360p",
+ "resolution480p": "480p",
+ "resolution720p": "720p",
+ "resolutionOriginal": "рдореВрд▓",
+ "resultTitle": "рд╕рдВрдкреАрдбрд╝рд┐рдд рд╡реАрдбрд┐рдпреЛ",
+ "title": "рд╡реАрдбрд┐рдпреЛ рд╕рдВрдкреАрдбрд╝рд┐рдд рдХрд░реЗрдВ",
+ "videoQuality": "рд╡реАрдбрд┐рдпреЛ рдЧреБрдгрд╡рддреНрддрд╛"
+ },
+ "cropVideo": {
+ "aspectRatio": "рдЖрдХрд╛рд░ рдЕрдиреБрдкрд╛рдд",
+ "cropArea": "рдХреНрд░реЙрдк рдХреНрд╖реЗрддреНрд░",
+ "cropMethod": "рдХреНрд░реЙрдк рд╡рд┐рдзрд┐",
+ "cropOptions": "рдХреНрд░реЙрдк рд╡рд┐рдХрд▓реНрдк",
+ "description": "рд╡реАрдбрд┐рдпреЛ рд╕реЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рднрд╛рдЧ рд╣рдЯрд╛рдПрдВред",
+ "height": "рдКрдВрдЪрд╛рдИ",
+ "heightPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡реАрдбрд┐рдпреЛ",
+ "methodAspectRatio": "рдЖрдХрд╛рд░ рдЕрдиреБрдкрд╛рдд",
+ "methodManual": "рдореИрдиреБрдЕрд▓",
+ "ratio16x9": "16:9",
+ "ratio1x1": "1:1",
+ "ratio4x3": "4:3",
+ "resultTitle": "рдХреНрд░реЙрдк рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╡реАрдбрд┐рдпреЛ",
+ "title": "рд╡реАрдбрд┐рдпреЛ рдХреНрд░реЙрдк рдХрд░реЗрдВ",
+ "width": "рдЪреМрдбрд╝рд╛рдИ",
+ "widthPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "xPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "xPosition": "X рд╕реНрдерд┐рддрд┐",
+ "yPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "yPosition": "Y рд╕реНрдерд┐рддрд┐"
+ },
+ "flip": {
+ "description": "рд╡реАрдбрд┐рдпреЛ рдХреЛ рдХреНрд╖реИрддрд┐рдЬ рдпрд╛ рд▓рдВрдмрд╡рдд рд░реВрдк рд╕реЗ рдлреНрд▓рд┐рдк рдХрд░реЗрдВред",
+ "directionBoth": "рджреЛрдиреЛрдВ",
+ "directionHorizontal": "рдХреНрд╖реИрддрд┐рдЬ",
+ "directionVertical": "рд▓рдВрдмрд╡рдд",
+ "flipDirection": "рдлреНрд▓рд┐рдк рджрд┐рд╢рд╛",
+ "flipOptions": "рдлреНрд▓рд┐рдк рд╡рд┐рдХрд▓реНрдк",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡реАрдбрд┐рдпреЛ",
+ "preserveAudio": "рдСрдбрд┐рдпреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "resultTitle": "рдлреНрд▓рд┐рдк рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╡реАрдбрд┐рдпреЛ",
+ "title": "рд╡реАрдбрд┐рдпреЛ рдлреНрд▓рд┐рдк рдХрд░реЗрдВ"
+ },
+ "gif": {
+ "changeSpeed": {
+ "delayPlaceholder": "рдорд┐рд▓реАрд╕реЗрдХрдВрдб",
+ "description": "GIF рдПрдирд┐рдореЗрдЯреЗрдб рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдЧрддрд┐ рдмрджрд▓реЗрдВред",
+ "factorPlaceholder": "рдХрд╛рд░рдХ (рдЬреИрд╕реЗ 0.5, 1.5, 2.0)",
+ "frameDelay": "рдлреНрд░реЗрдо рд╡рд┐рд▓рдВрдм",
+ "inputTitle": "рдЗрдирдкреБрдЯ GIF",
+ "resultTitle": "рдЧрддрд┐ рдмрджрд▓реА рдЧрдИ GIF",
+ "speedFactor": "рдЧрддрд┐ рдХрд╛рд░рдХ",
+ "speedOptions": "рдЧрддрд┐ рд╡рд┐рдХрд▓реНрдк",
+ "title": "GIF рдЧрддрд┐ рдмрджрд▓реЗрдВ"
+ }
+ },
+ "loop": {
+ "countPlaceholder": "рд╕рдВрдЦреНрдпрд╛",
+ "description": "рд╡реАрдбрд┐рдпреЛ рдХреЛ рд▓реВрдк рдореЗрдВ рдЪрд▓рд╛рдПрдВред",
+ "durationPlaceholder": "рд╕реЗрдХрдВрдб",
+ "fadeDuration": "рдлреЗрдб рдЕрд╡рдзрд┐",
+ "fadeTransition": "рдлреЗрдб рд╕рдВрдХреНрд░рдордг",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡реАрдбрд┐рдпреЛ",
+ "loopCount": "рд▓реВрдк рдХреА рд╕рдВрдЦреНрдпрд╛",
+ "loopInfinitely": "рдЕрдирдВрдд рд▓реВрдк",
+ "loopOptions": "рд▓реВрдк рд╡рд┐рдХрд▓реНрдк",
+ "resultTitle": "рд▓реВрдк рд╡реАрдбрд┐рдпреЛ",
+ "title": "рд╡реАрдбрд┐рдпреЛ рд▓реВрдк рдХрд░реЗрдВ"
+ },
+ "rotate": {
+ "angle180": "180 рдбрд┐рдЧреНрд░реА",
+ "angle270": "270 рдбрд┐рдЧреНрд░реА",
+ "angle90": "90 рдбрд┐рдЧреНрд░реА",
+ "customAngle": "рдХрд╕реНрдЯрдо рдХреЛрдг",
+ "customAnglePlaceholder": "рдбрд┐рдЧреНрд░реА",
+ "description": "рд╡реАрдбрд┐рдпреЛ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреЛрдг рд╕реЗ рдШреБрдорд╛рдПрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡реАрдбрд┐рдпреЛ",
+ "preserveAudio": "рдСрдбрд┐рдпреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "resultTitle": "рдШреБрдорд╛рдпрд╛ рдЧрдпрд╛ рд╡реАрдбрд┐рдпреЛ",
+ "rotationAngle": "рдШреБрдорд╛рдиреЗ рдХрд╛ рдХреЛрдг",
+ "rotationOptions": "рдШреБрдорд╛рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк",
+ "title": "рд╡реАрдбрд┐рдпреЛ рдШреБрдорд╛рдПрдВ"
+ },
+ "trim": {
+ "description": "рд╡реАрдбрд┐рдпреЛ рд╕реЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рднрд╛рдЧ рд╣рдЯрд╛рдПрдВред",
+ "endPlaceholder": "рд╕реЗрдХрдВрдб",
+ "endTime": "рдЕрдВрддрд┐рдо рд╕рдордп",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡реАрдбрд┐рдпреЛ",
+ "preserveAudio": "рдСрдбрд┐рдпреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "resultTitle": "рдЯреНрд░рд┐рдо рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╡реАрдбрд┐рдпреЛ",
+ "startPlaceholder": "рд╕реЗрдХрдВрдб",
+ "startTime": "рд╢реБрд░реБрдЖрддреА рд╕рдордп",
+ "title": "рд╡реАрдбрд┐рдпреЛ рдЯреНрд░рд┐рдо рдХрд░реЗрдВ",
+ "trimOptions": "рдЯреНрд░рд┐рдо рд╡рд┐рдХрд▓реНрдк"
+ },
+ "videoToGif": {
+ "conversionOptions": "рд░реВрдкрд╛рдВрддрд░рдг рд╡рд┐рдХрд▓реНрдк",
+ "description": "рд╡реАрдбрд┐рдпреЛ рдХреЛ GIF рдПрдирд┐рдореЗрдЯреЗрдб рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "frameRate": "рдлреНрд░реЗрдо рджрд░",
+ "frameRatePlaceholder": "FPS",
+ "height": "рдКрдВрдЪрд╛рдИ",
+ "heightPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓",
+ "inputTitle": "рдЗрдирдкреБрдЯ рд╡реАрдбрд┐рдпреЛ",
+ "quality": "рдЧреБрдгрд╡рддреНрддрд╛",
+ "qualityHigh": "рдЙрдЪреНрдЪ",
+ "qualityLow": "рдХрдо",
+ "qualityMedium": "рдордзреНрдпрдо",
+ "resize": "рдЖрдХрд╛рд░ рдмрджрд▓реЗрдВ",
+ "resultTitle": "GIF рдлрд╝рд╛рдЗрд▓",
+ "title": "рд╡реАрдбрд┐рдпреЛ рд╕реЗ GIF",
+ "width": "рдЪреМрдбрд╝рд╛рдИ",
+ "widthPlaceholder": "рдкрд┐рдХреНрд╕реЗрд▓"
+ }
+}
diff --git a/public/locales/hi/xml.json b/public/locales/hi/xml.json
new file mode 100644
index 0000000..86432c2
--- /dev/null
+++ b/public/locales/hi/xml.json
@@ -0,0 +1,42 @@
+{
+ "xmlBeautifier": {
+ "description": "XML рдХреЛ рд╕реБрдВрджрд░ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрджрд▓реЗрдВред",
+ "formattingOptions": "рдлреЙрд░реНрдореЗрдЯрд┐рдВрдЧ рд╡рд┐рдХрд▓реНрдк",
+ "indentCharacter": "рдЗрдВрдбреЗрдВрдЯ рд╡рд░реНрдг",
+ "indentSize": "рдЗрдВрдбреЗрдВрдЯ рдЖрдХрд╛рд░",
+ "inputTitle": "рдЗрдирдкреБрдЯ XML",
+ "preserveWhitespace": "рд╕рдлреЗрдж рд╕реНрдерд╛рди рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░реЗрдВ",
+ "removeComments": "рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдВ рд╣рдЯрд╛рдПрдВ",
+ "resultTitle": "рд╕реБрдВрджрд░ XML",
+ "sizePlaceholder": "рдЖрдХрд╛рд░",
+ "sortAttributes": "рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рдХреНрд░рдордмрджреНрдз рдХрд░реЗрдВ",
+ "space": "рд╕реНрдкреЗрд╕",
+ "tab": "рдЯреИрдм",
+ "title": "XML рд╕реБрдВрджрд░ рдмрдирд╛рдПрдВ"
+ },
+ "xmlValidator": {
+ "allowCDATA": "CDATA рдЕрдиреБрдорддрд┐ рджреЗрдВ",
+ "allowComments": "рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдВ рдЕрдиреБрдорддрд┐ рджреЗрдВ",
+ "description": "XML рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреА рд╡реИрдзрддрд╛ рдЬрд╛рдВрдЪреЗрдВред",
+ "inputTitle": "рдЗрдирдкреБрдЯ XML",
+ "resultTitle": "рдорд╛рдиреНрдпрддрд╛ рдкрд░рд┐рдгрд╛рдо",
+ "showErrorDetails": "рддреНрд░реБрдЯрд┐ рд╡рд┐рд╡рд░рдг рджрд┐рдЦрд╛рдПрдВ",
+ "showLineNumbers": "рдкрдВрдХреНрддрд┐ рд╕рдВрдЦреНрдпрд╛рдПрдВ рджрд┐рдЦрд╛рдПрдВ",
+ "strictMode": "рд╕рдЦреНрдд рдореЛрдб",
+ "title": "XML рдорд╛рдиреНрдп рдХрд░реЗрдВ",
+ "validationOptions": "рдорд╛рдиреНрдпрддрд╛ рд╡рд┐рдХрд▓реНрдк"
+ },
+ "xmlViewer": {
+ "collapseAll": "рд╕рднреА рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдХрд░реЗрдВ",
+ "description": "XML рдХреЛ рдкреЗрдбрд╝ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рджреЗрдЦреЗрдВред",
+ "expandAll": "рд╕рднреА рд╡рд┐рд╕реНрддрд╛рд░рд┐рдд рдХрд░реЗрдВ",
+ "highlightSyntax": "рд╕рд┐рдВрдЯреИрдХреНрд╕ рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд░реЗрдВ",
+ "inputTitle": "рдЗрдирдкреБрдЯ XML",
+ "lineNumbers": "рдкрдВрдХреНрддрд┐ рд╕рдВрдЦреНрдпрд╛рдПрдВ",
+ "resultTitle": "XML рдкреЗрдбрд╝",
+ "showAttributes": "рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рджрд┐рдЦрд╛рдПрдВ",
+ "showTextNodes": "рдЯреЗрдХреНрд╕реНрдЯ рдиреЛрдб рджрд┐рдЦрд╛рдПрдВ",
+ "title": "XML рд╡реНрдпреВрдЕрд░",
+ "viewerOptions": "рд╡реНрдпреВрдЕрд░ рд╡рд┐рдХрд▓реНрдк"
+ }
+}
diff --git a/public/locales/ja/audio.json b/public/locales/ja/audio.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/audio.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/csv.json b/public/locales/ja/csv.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/csv.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/image.json b/public/locales/ja/image.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/image.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/json.json b/public/locales/ja/json.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/json.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/list.json b/public/locales/ja/list.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/list.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/number.json b/public/locales/ja/number.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/number.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/pdf.json b/public/locales/ja/pdf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/pdf.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/string.json b/public/locales/ja/string.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/string.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/time.json b/public/locales/ja/time.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/time.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/translation.json b/public/locales/ja/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/video.json b/public/locales/ja/video.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/video.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ja/xml.json b/public/locales/ja/xml.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ja/xml.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/audio.json b/public/locales/nl/audio.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/audio.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/csv.json b/public/locales/nl/csv.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/csv.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/image.json b/public/locales/nl/image.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/image.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/json.json b/public/locales/nl/json.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/json.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/list.json b/public/locales/nl/list.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/list.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/number.json b/public/locales/nl/number.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/number.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/pdf.json b/public/locales/nl/pdf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/pdf.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/string.json b/public/locales/nl/string.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/string.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/time.json b/public/locales/nl/time.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/time.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/translation.json b/public/locales/nl/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/video.json b/public/locales/nl/video.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/video.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/nl/xml.json b/public/locales/nl/xml.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/nl/xml.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/audio.json b/public/locales/pt/audio.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/audio.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/csv.json b/public/locales/pt/csv.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/csv.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/image.json b/public/locales/pt/image.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/image.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/json.json b/public/locales/pt/json.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/json.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/list.json b/public/locales/pt/list.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/list.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/number.json b/public/locales/pt/number.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/number.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/pdf.json b/public/locales/pt/pdf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/pdf.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/string.json b/public/locales/pt/string.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/string.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/time.json b/public/locales/pt/time.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/time.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/translation.json b/public/locales/pt/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/video.json b/public/locales/pt/video.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/video.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/pt/xml.json b/public/locales/pt/xml.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/pt/xml.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/audio.json b/public/locales/ru/audio.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/audio.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/csv.json b/public/locales/ru/csv.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/csv.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/image.json b/public/locales/ru/image.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/image.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/json.json b/public/locales/ru/json.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/json.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/list.json b/public/locales/ru/list.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/list.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/number.json b/public/locales/ru/number.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/number.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/pdf.json b/public/locales/ru/pdf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/pdf.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/string.json b/public/locales/ru/string.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/string.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/time.json b/public/locales/ru/time.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/time.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/video.json b/public/locales/ru/video.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/video.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/ru/xml.json b/public/locales/ru/xml.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/ru/xml.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/audio.json b/public/locales/zh/audio.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/audio.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/csv.json b/public/locales/zh/csv.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/csv.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/image.json b/public/locales/zh/image.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/image.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/json.json b/public/locales/zh/json.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/json.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/list.json b/public/locales/zh/list.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/list.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/number.json b/public/locales/zh/number.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/number.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/pdf.json b/public/locales/zh/pdf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/pdf.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/string.json b/public/locales/zh/string.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/string.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/time.json b/public/locales/zh/time.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/time.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/video.json b/public/locales/zh/video.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/video.json
@@ -0,0 +1 @@
+{}
diff --git a/public/locales/zh/xml.json b/public/locales/zh/xml.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/public/locales/zh/xml.json
@@ -0,0 +1 @@
+{}
diff --git a/scripts/add-i18n-to-meta.js b/scripts/add-i18n-to-meta.js
new file mode 100644
index 0000000..b5fac00
--- /dev/null
+++ b/scripts/add-i18n-to-meta.js
@@ -0,0 +1,260 @@
+const fs = require('fs');
+const path = require('path');
+
+const TYPE_MAPPING = { 'image-generic': 'image', png: 'image' };
+// Helper function to convert kebab-case to camelCase
+function toCamelCase(str) {
+ return str.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
+}
+
+// Helper function to parse meta.ts file and extract required fields
+function parseMeta(filePath) {
+ const content = fs.readFileSync(filePath, 'utf8');
+
+ // Extract category from defineTool first parameter
+ const categoryMatch = content.match(/defineTool\s*\(\s*['"]([^'"]+)['"]/);
+ if (!categoryMatch) {
+ throw new Error(`Could not find category in ${filePath}`);
+ }
+ const category = categoryMatch[1];
+
+ // Extract name, description, shortDescription, and longDescription
+ const nameMatch = content.match(/name\s*:\s*['"`]([^'"`]+)['"`]/);
+ const descMatch = content.match(/description\s*:\s*['"`]([\s\S]*?)['"`]/);
+ const shortMatch = content.match(
+ /shortDescription\s*:\s*['"`]([^'"`]+)['"`]/
+ );
+ const longMatch = content.match(/longDescription\s*:\s*['"`]([\s\S]*?)['"`]/);
+
+ if (!nameMatch || !descMatch || !shortMatch) {
+ console.warn(`тЪая╕П Missing required fields in ${filePath}`);
+ console.warn(
+ ` name: ${!!nameMatch}, description: ${!!descMatch}, shortDescription: ${!!shortMatch}`
+ );
+ return null;
+ }
+
+ return {
+ category,
+ name: nameMatch[1],
+ description: descMatch[1].replace(/\s+/g, ' ').trim(),
+ shortDescription: shortMatch[1],
+ longDescription: longMatch ? longMatch[1].replace(/\s+/g, ' ').trim() : null
+ };
+}
+
+// Helper function to check if meta.ts already has i18n field
+function hasI18nField(filePath) {
+ const content = fs.readFileSync(filePath, 'utf8');
+ return content.includes('i18n:');
+}
+
+// Helper function to add i18n field to meta.ts
+function addI18nToMeta(filePath, category, toolName, hasLongDescription) {
+ const content = fs.readFileSync(filePath, 'utf8');
+
+ // Build i18n object
+ let i18nObject = ` i18n: {
+ name: '${category}:${toolName}.title',
+ description: '${category}:${toolName}.description',
+ shortDescription: '${category}:${toolName}.shortDescription'`;
+
+ if (hasLongDescription) {
+ i18nObject += `,
+ longDescription: '${category}:${toolName}.longDescription'`;
+ }
+
+ i18nObject += `
+ },`;
+
+ // Find the position to insert i18n (after the export line but before the closing bracket)
+ const exportMatch = content.match(/export const tool = defineTool\([^{]*\{/);
+ if (!exportMatch) {
+ throw new Error(`Could not find export structure in ${filePath}`);
+ }
+
+ const insertPosition = exportMatch.index + exportMatch[0].length;
+ const beforeInsert = content.substring(0, insertPosition);
+ const afterInsert = content.substring(insertPosition);
+
+ // Insert i18n field at the beginning of the object
+ const updatedContent = beforeInsert + '\n' + i18nObject + afterInsert;
+
+ fs.writeFileSync(filePath, updatedContent, 'utf8');
+}
+
+// Helper function to get category i18n file path
+function getCategoryI18nPath(category) {
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
+ // Special case: image-generic tools use the image folder for i18n
+ const folderName = TYPE_MAPPING[category] || category;
+ return path.join(
+ PROJECT_ROOT,
+ 'src',
+ 'pages',
+ 'tools',
+ folderName,
+ 'i18n',
+ 'en.json'
+ );
+}
+
+// Helper function to load category i18n data
+function loadCategoryI18n(category) {
+ const i18nPath = getCategoryI18nPath(category);
+
+ try {
+ if (fs.existsSync(i18nPath)) {
+ const i18nRaw = fs.readFileSync(i18nPath, 'utf8');
+ return JSON.parse(i18nRaw);
+ } else {
+ const i18nDir = path.dirname(i18nPath);
+ if (!fs.existsSync(i18nDir)) {
+ fs.mkdirSync(i18nDir, { recursive: true });
+ }
+ return {};
+ }
+ } catch (err) {
+ console.error(`тЭМ Failed to parse ${i18nPath}:`, err.message);
+ return {};
+ }
+}
+
+// Helper function to save category i18n data
+function saveCategoryI18n(category, data) {
+ const i18nPath = getCategoryI18nPath(category);
+ fs.writeFileSync(i18nPath, JSON.stringify(data, null, 2) + '\n', 'utf8');
+ return i18nPath;
+}
+
+// Main execution
+console.log('ЁЯЪА Adding i18n fields to meta.ts files...\n');
+
+const PROJECT_ROOT = path.resolve(__dirname, '..');
+
+// Target files as specified
+const rootDir = path.join(PROJECT_ROOT, 'src/pages/tools');
+const metaFiles = [];
+
+function findMetaFiles(dir) {
+ const items = fs.readdirSync(dir, { withFileTypes: true });
+
+ for (const item of items) {
+ const fullPath = path.join(dir, item.name);
+
+ if (item.isDirectory()) {
+ findMetaFiles(fullPath); // Recurse
+ } else if (item.isFile() && item.name === 'meta.ts') {
+ metaFiles.push(fullPath);
+ }
+ }
+}
+
+findMetaFiles(rootDir);
+
+let processedCount = 0;
+let skippedCount = 0;
+let errorCount = 0;
+const updatedCategories = new Set();
+const categoryData = {};
+
+// Process each target file
+metaFiles.forEach((filePath) => {
+ try {
+ // Check if file exists
+ if (!fs.existsSync(filePath)) {
+ console.error(`тЭМ File not found: ${filePath}`);
+ errorCount++;
+ return;
+ }
+
+ // Check if i18n field already exists
+ if (hasI18nField(filePath)) {
+ console.log(`тПня╕П Skipped ${filePath} (already has i18n field)`);
+ skippedCount++;
+ return;
+ }
+
+ // Parse meta.ts file
+ const parsed = parseMeta(filePath);
+ if (!parsed) {
+ errorCount++;
+ return;
+ }
+
+ const {
+ category: rawCategory,
+ name,
+ description,
+ shortDescription,
+ longDescription
+ } = parsed;
+
+ const category = TYPE_MAPPING[rawCategory] || rawCategory;
+ // Get tool name from folder path
+ const toolFolderName = path.basename(path.dirname(filePath));
+ const toolKey = toCamelCase(toolFolderName); // camelCase for i18n file keys
+
+ // Load category i18n data if not already loaded
+ if (!categoryData[category]) {
+ categoryData[category] = loadCategoryI18n(category);
+ }
+
+ // Ensure tool entry exists in i18n
+ if (!categoryData[category][toolKey]) {
+ categoryData[category][toolKey] = {};
+ }
+
+ const entry = categoryData[category][toolKey];
+ let hasI18nChanges = false;
+
+ // Add missing fields to i18n
+ if (!entry.title) {
+ entry.title = name;
+ hasI18nChanges = true;
+ }
+ if (!entry.description) {
+ entry.description = description;
+ hasI18nChanges = true;
+ }
+ if (!entry.shortDescription) {
+ entry.shortDescription = shortDescription;
+ hasI18nChanges = true;
+ }
+ if (longDescription && !entry.longDescription) {
+ entry.longDescription = longDescription;
+ hasI18nChanges = true;
+ }
+
+ // Add i18n field to meta.ts
+ addI18nToMeta(filePath, category, toolKey, !!longDescription);
+
+ if (hasI18nChanges) {
+ updatedCategories.add(category);
+ }
+
+ console.log(`тЬЕ Added i18n to ${filePath}`);
+ processedCount++;
+ } catch (err) {
+ console.error(`тЭМ Error processing ${filePath}:`, err.message);
+ errorCount++;
+ }
+});
+
+// Save updated category i18n files
+if (updatedCategories.size > 0) {
+ console.log('\nЁЯТ╛ Saving updated i18n files...');
+ for (const category of updatedCategories) {
+ const savedPath = saveCategoryI18n(category, categoryData[category]);
+ console.log(` ЁЯУБ ${path.relative(PROJECT_ROOT, savedPath)}`);
+ }
+}
+
+// Summary
+console.log('\nЁЯУК Summary:');
+console.log(` тЬЕ Processed: ${processedCount} files`);
+console.log(` тПня╕П Skipped: ${skippedCount} files (already had i18n)`);
+console.log(` тЭМ Errors: ${errorCount} files`);
+console.log(
+ `\nЁЯОЙ Successfully updated ${processedCount} meta.ts files and ${updatedCategories.size} i18n files!`
+);
diff --git a/scripts/locize-upload.js b/scripts/locize-upload.js
new file mode 100644
index 0000000..6099a3d
--- /dev/null
+++ b/scripts/locize-upload.js
@@ -0,0 +1,213 @@
+// one-time-upload.js
+// Simple script to upload your existing translations to Locize once
+
+const fs = require('fs');
+const https = require('https');
+
+// Configuration
+const LOCIZE_PROJECT_ID = 'e7156a3e-66fb-4035-a0f0-cebf1c63a3ba';
+const LOCIZE_API_KEY = process.env.LOCIZE_API_KEY; // Replace with your actual API key
+const LOCIZE_VERSION = 'latest';
+
+// Define your translation files
+const translationFiles = [
+ // English translations
+ { lang: 'en', namespace: 'translation', file: '../src/i18n/en.json' },
+ {
+ lang: 'en',
+ namespace: 'list',
+ file: '../src/pages/tools/list/i18n/en.json'
+ },
+ {
+ lang: 'en',
+ namespace: 'string',
+ file: '../src/pages/tools/string/i18n/en.json'
+ },
+ { lang: 'en', namespace: 'csv', file: '../src/pages/tools/csv/i18n/en.json' },
+ {
+ lang: 'en',
+ namespace: 'json',
+ file: '../src/pages/tools/json/i18n/en.json'
+ },
+ { lang: 'en', namespace: 'pdf', file: '../src/pages/tools/pdf/i18n/en.json' },
+ {
+ lang: 'en',
+ namespace: 'image',
+ file: '../src/pages/tools/image/i18n/en.json'
+ },
+ {
+ lang: 'en',
+ namespace: 'audio',
+ file: '../src/pages/tools/audio/i18n/en.json'
+ },
+ {
+ lang: 'en',
+ namespace: 'video',
+ file: '../src/pages/tools/video/i18n/en.json'
+ },
+ {
+ lang: 'en',
+ namespace: 'number',
+ file: '../src/pages/tools/number/i18n/en.json'
+ },
+ {
+ lang: 'en',
+ namespace: 'time',
+ file: '../src/pages/tools/time/i18n/en.json'
+ },
+ { lang: 'en', namespace: 'xml', file: '../src/pages/tools/xml/i18n/en.json' },
+
+ // Hindi translations
+ { lang: 'hi', namespace: 'translation', file: '../src/i18n/hi.json' },
+ {
+ lang: 'hi',
+ namespace: 'list',
+ file: '../src/pages/tools/list/i18n/hi.json'
+ },
+ {
+ lang: 'hi',
+ namespace: 'string',
+ file: '../src/pages/tools/string/i18n/hi.json'
+ },
+ { lang: 'hi', namespace: 'csv', file: '../src/pages/tools/csv/i18n/hi.json' },
+ {
+ lang: 'hi',
+ namespace: 'json',
+ file: '../src/pages/tools/json/i18n/hi.json'
+ },
+ { lang: 'hi', namespace: 'pdf', file: '../src/pages/tools/pdf/i18n/hi.json' },
+ {
+ lang: 'hi',
+ namespace: 'image',
+ file: '../src/pages/tools/image/i18n/hi.json'
+ },
+ {
+ lang: 'hi',
+ namespace: 'audio',
+ file: '../src/pages/tools/audio/i18n/hi.json'
+ },
+ {
+ lang: 'hi',
+ namespace: 'video',
+ file: '../src/pages/tools/video/i18n/hi.json'
+ },
+ {
+ lang: 'hi',
+ namespace: 'number',
+ file: '../src/pages/tools/number/i18n/hi.json'
+ },
+ {
+ lang: 'hi',
+ namespace: 'time',
+ file: '../src/pages/tools/time/i18n/hi.json'
+ },
+ { lang: 'hi', namespace: 'xml', file: '../src/pages/tools/xml/i18n/hi.json' }
+];
+
+function flattenJson(obj, prefix = '') {
+ const flattened = {};
+
+ for (const key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ const newKey = prefix ? `${prefix}.${key}` : key;
+
+ if (
+ typeof obj[key] === 'object' &&
+ obj[key] !== null &&
+ !Array.isArray(obj[key])
+ ) {
+ // Recursively flatten nested objects
+ Object.assign(flattened, flattenJson(obj[key], newKey));
+ } else {
+ // It's a primitive value or array
+ flattened[newKey] = obj[key];
+ }
+ }
+ }
+
+ return flattened;
+}
+
+function uploadToLocize(lang, namespace, data) {
+ return new Promise((resolve, reject) => {
+ // Flatten the JSON structure for Locize API
+ const flattenedData = flattenJson(data);
+ const postData = JSON.stringify(flattenedData);
+
+ const options = {
+ hostname: 'api.locize.app',
+ port: 443,
+ path: `/update/${LOCIZE_PROJECT_ID}/${LOCIZE_VERSION}/${lang}/${namespace}`,
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${LOCIZE_API_KEY}`,
+ 'Content-Type': 'application/json',
+ 'Content-Length': Buffer.byteLength(postData)
+ }
+ };
+
+ const req = https.request(options, (res) => {
+ let data = '';
+ res.on('data', (chunk) => (data += chunk));
+ res.on('end', () => {
+ if (res.statusCode === 200) {
+ resolve(JSON.parse(data));
+ } else {
+ reject(new Error(`HTTP ${res.statusCode}: ${data}`));
+ }
+ });
+ });
+
+ req.on('error', reject);
+ req.write(postData);
+ req.end();
+ });
+}
+
+async function main() {
+ console.log('Starting one-time upload to Locize...\n');
+
+ let successCount = 0;
+ let errorCount = 0;
+
+ for (const { lang, namespace, file } of translationFiles) {
+ try {
+ // Check if file exists
+ if (!fs.existsSync(file)) {
+ console.log(`тЪая╕П File not found: ${file}`);
+ continue;
+ }
+
+ // Read translation file
+ const translations = JSON.parse(fs.readFileSync(file, 'utf8'));
+ const flattenedTranslations = flattenJson(translations);
+ const keyCount = Object.keys(flattenedTranslations).length;
+
+ if (keyCount === 0) {
+ console.log(`тЪая╕П Empty file: ${lang}/${namespace}`);
+ continue;
+ }
+
+ // Upload to Locize
+ await uploadToLocize(lang, namespace, translations);
+ console.log(`тЬЕ ${lang}/${namespace} - ${keyCount} keys uploaded`);
+ successCount++;
+ } catch (error) {
+ console.error(`тЭМ ${lang}/${namespace} - Error: ${error.message}`);
+ errorCount++;
+ }
+ }
+
+ console.log('\n=== Upload Summary ===');
+ console.log(`тЬЕ Successful uploads: ${successCount}`);
+ console.log(`тЭМ Failed uploads: ${errorCount}`);
+ console.log(`ЁЯУК Total files processed: ${successCount + errorCount}`);
+
+ if (errorCount === 0) {
+ console.log('\nЁЯОЙ All translations uploaded successfully!');
+ console.log('You can now view them in your Locize dashboard.');
+ }
+}
+
+// Run the upload
+main().catch(console.error);
diff --git a/scripts/update-i18n-from-meta.js b/scripts/update-i18n-from-meta.js
new file mode 100644
index 0000000..bba4d8f
--- /dev/null
+++ b/scripts/update-i18n-from-meta.js
@@ -0,0 +1,203 @@
+const fs = require('fs');
+const path = require('path');
+
+// Helper function to convert kebab-case to camelCase
+function toCamelCase(str) {
+ return str.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
+}
+
+// Helper function to recursively find all meta.ts files
+function findMetaFiles(dir) {
+ const files = [];
+
+ function traverse(currentDir) {
+ const items = fs.readdirSync(currentDir, { withFileTypes: true });
+
+ for (const item of items) {
+ const fullPath = path.join(currentDir, item.name);
+
+ if (item.isDirectory()) {
+ traverse(fullPath);
+ } else if (item.name === 'meta.ts') {
+ files.push(fullPath);
+ }
+ }
+ }
+
+ traverse(dir);
+ return files;
+}
+
+// Helper function to parse meta.ts file and extract the required fields
+function parseMeta(filePath) {
+ const content = fs.readFileSync(filePath, 'utf8');
+
+ // Extract category from defineTool first parameter
+ const categoryMatch = content.match(/defineTool\s*\(\s*['"]([^'"]+)['"]/);
+ if (!categoryMatch) {
+ throw new Error(`Could not find category in ${filePath}`);
+ }
+ const category = categoryMatch[1];
+
+ // Extract name, description, and shortDescription
+ const nameMatch = content.match(/name\s*:\s*['"`]([^'"`]+)['"`]/);
+ const descMatch = content.match(
+ /description\s*:\s*['"`]([\s\S]*?)['"`]\s*,\s*shortDescription/
+ );
+ const shortMatch = content.match(
+ /shortDescription\s*:\s*['"`]([^'"`]+)['"`]/
+ );
+
+ if (!nameMatch || !descMatch || !shortMatch) {
+ console.warn(`тЪая╕П Missing fields in ${filePath}`);
+ console.warn(
+ ` name: ${!!nameMatch}, description: ${!!descMatch}, shortDescription: ${!!shortMatch}`
+ );
+ return null;
+ }
+
+ return {
+ category,
+ name: nameMatch[1],
+ description: descMatch[1].replace(/\s+/g, ' ').trim(),
+ shortDescription: shortMatch[1]
+ };
+}
+
+// Main execution
+console.log('ЁЯЪА Starting i18n extraction from meta.ts files...\n');
+
+const PROJECT_ROOT = path.resolve(__dirname, '..');
+
+// Helper function to get or create category i18n file
+function getCategoryI18nPath(category) {
+ return path.join(
+ PROJECT_ROOT,
+ 'src',
+ 'pages',
+ 'tools',
+ category,
+ 'i18n',
+ 'en.json'
+ );
+}
+
+function loadCategoryI18n(category) {
+ const i18nPath = getCategoryI18nPath(category);
+
+ try {
+ if (fs.existsSync(i18nPath)) {
+ const i18nRaw = fs.readFileSync(i18nPath, 'utf8');
+ return JSON.parse(i18nRaw);
+ } else {
+ // Create directory if it doesn't exist
+ const i18nDir = path.dirname(i18nPath);
+ if (!fs.existsSync(i18nDir)) {
+ fs.mkdirSync(i18nDir, { recursive: true });
+ }
+ return {};
+ }
+ } catch (err) {
+ console.error(`тЭМ Failed to parse ${i18nPath}:`, err.message);
+ return {};
+ }
+}
+
+function saveCategoryI18n(category, data) {
+ const i18nPath = getCategoryI18nPath(category);
+
+ // Create backup
+ // if (fs.existsSync(i18nPath)) {
+ // fs.copyFileSync(i18nPath, i18nPath + '.bak');
+ // }
+
+ // Write updated file
+ fs.writeFileSync(i18nPath, JSON.stringify(data, null, 2) + '\n', 'utf8');
+ return i18nPath;
+}
+
+// 2) Find all meta.ts files under src/pages/tools
+const toolsDir = path.join(PROJECT_ROOT, 'src', 'pages', 'tools');
+const files = findMetaFiles(toolsDir);
+console.log(`ЁЯУБ Found ${files.length} meta.ts files\n`);
+
+let addedCount = 0;
+let skippedCount = 0;
+let errorCount = 0;
+const updatedCategories = new Set();
+
+// 3) Process each meta.ts file
+const categoryData = {};
+
+files.forEach((file) => {
+ try {
+ const relativePath = path.relative(PROJECT_ROOT, file);
+ const parsed = parseMeta(file);
+
+ if (!parsed) {
+ errorCount++;
+ return;
+ }
+
+ const { category, name, description, shortDescription } = parsed;
+
+ // Load category i18n data if not already loaded
+ if (!categoryData[category]) {
+ categoryData[category] = loadCategoryI18n(category);
+ }
+
+ // Get tool key from folder name (convert kebab-case to camelCase)
+ const toolSlug = path.basename(path.dirname(file));
+ const toolKey = toCamelCase(toolSlug);
+
+ // Ensure tool entry exists
+ if (!categoryData[category][toolKey]) {
+ categoryData[category][toolKey] = {};
+ }
+
+ const entry = categoryData[category][toolKey];
+ let hasChanges = false;
+
+ // Add missing fields
+ if (!entry.name) {
+ entry.name = name;
+ hasChanges = true;
+ }
+ if (!entry.description) {
+ entry.description = description;
+ hasChanges = true;
+ }
+ if (!entry.shortDescription) {
+ entry.shortDescription = shortDescription;
+ hasChanges = true;
+ }
+
+ if (hasChanges) {
+ console.log(`тЬЕ Updated ${category}/${toolKey}`);
+ addedCount++;
+ updatedCategories.add(category);
+ } else {
+ console.log(`тПня╕П Skipped ${category}/${toolKey} (already exists)`);
+ skippedCount++;
+ }
+ } catch (err) {
+ console.error(`тЭМ Error processing ${file}:`, err.message);
+ errorCount++;
+ }
+});
+
+// 4) Save updated category i18n files
+console.log('\nЁЯТ╛ Saving updated i18n files...');
+for (const category of updatedCategories) {
+ const savedPath = saveCategoryI18n(category, categoryData[category]);
+ console.log(` ЁЯУБ ${path.relative(PROJECT_ROOT, savedPath)}`);
+}
+
+// 6) Summary
+console.log('\nЁЯУК Summary:');
+console.log(` тЬЕ Updated: ${addedCount} tools`);
+console.log(` тПня╕П Skipped: ${skippedCount} tools (already had entries)`);
+console.log(` тЭМ Errors: ${errorCount} tools`);
+console.log(
+ `\nЁЯОЙ Successfully updated ${updatedCategories.size} category i18n files!`
+);
diff --git a/src/components/App.tsx b/src/components/App.tsx
index 69d4d36..b71abd8 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -10,6 +10,8 @@ import { tools } from '../tools';
import './index.css';
import { darkTheme, lightTheme } from '../config/muiConfig';
import ScrollToTopButton from './ScrollToTopButton';
+import { I18nextProvider } from 'react-i18next';
+import i18n from '../i18n';
export type Mode = 'dark' | 'light' | 'system';
@@ -44,32 +46,34 @@ function App() {
}, []);
return (
-
-
-
-
-
- {
- setMode((prev) => nextMode(prev));
- localStorage.setItem('theme', nextMode(mode));
- }}
- />
- }>
-
-
-
-
-
-
-
+
+
+
+
+
+
+ {
+ setMode((prev) => nextMode(prev));
+ localStorage.setItem('theme', nextMode(mode));
+ }}
+ />
+ }>
+
+
+
+
+
+
+
+
);
}
diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx
index 9a2ebe0..ba2bc9d 100644
--- a/src/components/Hero.tsx
+++ b/src/components/Hero.tsx
@@ -15,9 +15,10 @@ import { useState } from 'react';
import { DefinedTool } from '@tools/defineTool';
import { filterTools, tools } from '@tools/index';
import { useNavigate } from 'react-router-dom';
-import _ from 'lodash';
import { Icon } from '@iconify/react';
import { getToolCategoryTitle } from '@utils/string';
+import { useTranslation } from 'react-i18next';
+import { validNamespaces } from '../i18n';
import {
getBookmarkedToolPaths,
isBookmarked,
@@ -44,21 +45,9 @@ type ToolInfo = {
label: string;
url: string;
};
-const exampleTools: ToolInfo[] = [
- {
- label: 'Create a transparent image',
- url: '/image-generic/create-transparent'
- },
- { label: 'Prettify JSON', url: '/json/prettify' },
- { label: 'Change GIF speed', url: '/gif/change-speed' },
- { label: 'Sort a list', url: '/list/sort' },
- { label: 'Compress PNG', url: '/png/compress-png' },
- { label: 'Split a text', url: '/string/split' },
- { label: 'Split PDF', url: '/pdf/split-pdf' },
- { label: 'Trim video', url: '/video/trim' },
- { label: 'Calculate number sum', url: '/number/sum' }
-];
+
export default function Hero() {
+ const { t } = useTranslation(validNamespaces);
const [inputValue, setInputValue] = useState('');
const theme = useTheme();
const [filteredTools, setFilteredTools] = useState(tools);
@@ -66,12 +55,52 @@ export default function Hero() {
getBookmarkedToolPaths()
);
const navigate = useNavigate();
+
+ const exampleTools: ToolInfo[] = [
+ {
+ label: t('translation:hero.examples.createTransparentImage'),
+ url: '/image-generic/create-transparent'
+ },
+ {
+ label: t('translation:hero.examples.prettifyJson'),
+ url: '/json/prettify'
+ },
+ {
+ label: t('translation:hero.examples.changeGifSpeed'),
+ url: '/gif/change-speed'
+ },
+ {
+ label: t('translation:hero.examples.sortList'),
+ url: '/list/sort'
+ },
+ {
+ label: t('translation:hero.examples.compressPng'),
+ url: '/png/compress-png'
+ },
+ {
+ label: t('translation:hero.examples.splitText'),
+ url: '/string/split'
+ },
+ {
+ label: t('translation:hero.examples.splitPdf'),
+ url: '/pdf/split-pdf'
+ },
+ {
+ label: t('translation:hero.examples.trimVideo'),
+ url: '/video/trim'
+ },
+ {
+ label: t('translation:hero.examples.calculateNumberSum'),
+ url: '/number/sum'
+ }
+ ];
+
const handleInputChange = (
event: React.ChangeEvent<{}>,
newInputValue: string
) => {
setInputValue(newInputValue);
- setFilteredTools(filterTools(tools, newInputValue));
+ setFilteredTools(filterTools(tools, newInputValue, t));
};
const toolsMap = new Map();
for (const tool of filteredTools) {
@@ -96,13 +125,13 @@ export default function Hero() {
- Get Things Done Quickly with{' '}
+ {t('translation:hero.title')}{' '}
- OmniTools
+ {t('translation:hero.brand')}
@@ -111,9 +140,7 @@ export default function Hero() {
fontSize={{ xs: 15, md: 20 }}
mb={2}
>
- Boost your productivity with OmniTools, the ultimate toolkit for getting
- things done quickly! Access thousands of user-friendly utilities for
- editing images, text, lists, and data, all directly from your browser.
+ {t('translation:hero.description')}
option.name}
+ getOptionLabel={(option) => t(option.name)}
renderInput={(params) => (
,
diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx
index 5b1bfcf..6677266 100644
--- a/src/components/Navbar/index.tsx
+++ b/src/components/Navbar/index.tsx
@@ -13,22 +13,39 @@ import {
ListItem,
ListItemButton,
ListItemText,
- Stack
+ Stack,
+ Select,
+ MenuItem,
+ FormControl
} from '@mui/material';
import useMediaQuery from '@mui/material/useMediaQuery';
import { useTheme } from '@mui/material/styles';
import { Icon } from '@iconify/react';
import { Mode } from 'components/App';
+import { useTranslation } from 'react-i18next';
interface NavbarProps {
mode: Mode;
onChangeMode: () => void;
}
+const languages = [
+ { code: 'en', label: 'English' },
+ { code: 'de', label: 'Deutsch' },
+ { code: 'es', label: 'Espa├▒ol' },
+ { code: 'fr', label: 'Fran├зais' },
+ { code: 'pt', label: 'Portugu├кs' },
+ { code: 'ja', label: 'цЧецЬмшкЮ' },
+ { code: 'hi', label: 'рд╣рд┐рдВрджреА' },
+ { code: 'nl', label: 'Nederlands' },
+ { code: 'ru', label: '╨а╤Г╤Б╤Б╨║╨╕╨╣' },
+ { code: 'zh', label: 'ф╕нцЦЗ' }
+];
const Navbar: React.FC = ({
mode,
onChangeMode: onChangeMode
}) => {
+ const { t, i18n } = useTranslation();
const navigate = useNavigate();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
@@ -36,12 +53,51 @@ const Navbar: React.FC = ({
const toggleDrawer = (open: boolean) => () => {
setDrawerOpen(open);
};
+
+ const handleLanguageChange = (event: any) => {
+ const newLanguage = event.target.value;
+ i18n.changeLanguage(newLanguage);
+ localStorage.setItem('lang', newLanguage);
+ };
+
const navItems: { label: string; path: string }[] = [
// { label: 'Features', path: '/features' }
// { label: 'About Us', path: '/about-us' }
];
+ const languageSelector = (
+
+
+
+ );
+
const buttons: ReactNode[] = [
+ languageSelector,
= ({
/>
}
>
- Buy me a coffee
+ {t('navbar.buyMeACoffee')}
];
const drawerList = (
diff --git a/src/components/ToolHeader.tsx b/src/components/ToolHeader.tsx
index fa24afb..47292f8 100644
--- a/src/components/ToolHeader.tsx
+++ b/src/components/ToolHeader.tsx
@@ -9,6 +9,7 @@ import { getToolsByCategory } from '@tools/index';
import { useEffect, useState } from 'react';
import { isBookmarked, toggleBookmarked } from '@utils/bookmark';
import IconButton from '@mui/material/IconButton';
+import { useTranslation } from 'react-i18next';
const StyledButton = styled(Button)(({ theme }) => ({
backgroundColor: 'white',
@@ -27,6 +28,7 @@ interface ToolHeaderProps {
}
function ToolLinks() {
+ const { t } = useTranslation();
const [examplesVisible, setExamplesVisible] = useState(false);
useEffect(() => {
@@ -66,7 +68,7 @@ function ToolLinks() {
sx={{ backgroundColor: 'background.paper' }}
onClick={() => scrollToElement('examples')}
>
- See Examples
+ {t('toolHeader.seeExamples')}
)}
diff --git a/src/components/ToolLayout.tsx b/src/components/ToolLayout.tsx
index 1b2e50b..7f127c8 100644
--- a/src/components/ToolLayout.tsx
+++ b/src/components/ToolLayout.tsx
@@ -5,28 +5,47 @@ import ToolHeader from './ToolHeader';
import Separator from './Separator';
import AllTools from './allTools/AllTools';
import { getToolsByCategory } from '@tools/index';
-import { capitalizeFirstLetter } from '../utils/string';
+import {
+ capitalizeFirstLetter,
+ getI18nNamespaceFromToolCategory
+} from '../utils/string';
import { IconifyIcon } from '@iconify/react';
+import { useTranslation } from 'react-i18next';
+import { ToolCategory } from '@tools/defineTool';
+import { FullI18nKey } from '../i18n';
export default function ToolLayout({
children,
- title,
- description,
icon,
+ i18n,
type,
fullPath
}: {
- title: string;
- description: string;
icon?: IconifyIcon | string;
- type: string;
+ type: ToolCategory;
fullPath: string;
children: ReactNode;
+ i18n?: {
+ name: FullI18nKey;
+ description: FullI18nKey;
+ shortDescription: FullI18nKey;
+ };
}) {
+ const { t } = useTranslation([
+ 'translation',
+ getI18nNamespaceFromToolCategory(type)
+ ]);
+
+ // Use i18n keys if available, otherwise fall back to provided strings
+ //@ts-ignore
+ const toolTitle: string = t(i18n.name);
+ //@ts-ignore
+ const toolDescription: string = t(i18n.description);
+
const otherCategoryTools =
getToolsByCategory()
.find((category) => category.type === type)
- ?.tools.filter((tool) => tool.name !== title)
+ ?.tools.filter((tool) => t(tool.name) !== toolTitle)
.map((tool) => ({
title: tool.name,
description: tool.shortDescription,
@@ -43,12 +62,12 @@ export default function ToolLayout({
sx={{ backgroundColor: 'background.default' }}
>
- {`${title} - OmniTools`}
+ {`${toolTitle} - OmniTools`}
category.type === type)!
- .rawTitle
- )} tools`}
+ title={t('toolLayout.allToolsTitle', {
+ type: capitalizeFirstLetter(
+ getToolsByCategory().find((category) => category.type === type)!
+ .rawTitle
+ )
+ })}
toolCards={otherCategoryTools}
/>
diff --git a/src/components/allTools/AllTools.tsx b/src/components/allTools/AllTools.tsx
index 06d663b..bd447e0 100644
--- a/src/components/allTools/AllTools.tsx
+++ b/src/components/allTools/AllTools.tsx
@@ -1,10 +1,12 @@
import { Box, Grid, Stack, Typography } from '@mui/material';
import ToolCard from './ToolCard';
import { IconifyIcon } from '@iconify/react';
+import { useTranslation } from 'react-i18next';
+import { FullI18nKey } from '../../i18n';
export interface ToolCardProps {
- title: string;
- description: string;
+ title: FullI18nKey;
+ description: FullI18nKey;
link: string;
icon: IconifyIcon | string;
}
@@ -15,6 +17,7 @@ interface AllToolsProps {
}
export default function AllTools({ title, toolCards }: AllToolsProps) {
+ const { t } = useTranslation();
return (
@@ -25,8 +28,10 @@ export default function AllTools({ title, toolCards }: AllToolsProps) {
{toolCards.map((card, index) => (
diff --git a/src/components/examples/ToolExamples.tsx b/src/components/examples/ToolExamples.tsx
index c1c00c6..1b87f16 100644
--- a/src/components/examples/ToolExamples.tsx
+++ b/src/components/examples/ToolExamples.tsx
@@ -3,6 +3,7 @@ import ExampleCard, { ExampleCardProps } from './ExampleCard';
import React from 'react';
import { GetGroupsType } from '@components/options/ToolOptions';
import { useFormikContext } from 'formik';
+import { useTranslation } from 'react-i18next';
export type CardExampleType = Omit<
ExampleCardProps,
@@ -24,6 +25,7 @@ export default function ToolExamples({
getGroups,
setInput
}: ExampleProps) {
+ const { t } = useTranslation();
const { setValues } = useFormikContext();
function changeInputResult(newInput: string | undefined, newOptions: T) {
@@ -39,10 +41,10 @@ export default function ToolExamples({
- {`${title} Examples`}
+ {t('toolExamples.title', { title })}
- {subtitle ?? 'Click to try!'}
+ {subtitle ?? t('toolExamples.subtitle')}
diff --git a/src/components/input/BaseFileInput.tsx b/src/components/input/BaseFileInput.tsx
index ebc3840..6502e6c 100644
--- a/src/components/input/BaseFileInput.tsx
+++ b/src/components/input/BaseFileInput.tsx
@@ -12,6 +12,7 @@ import { globalInputHeight } from '../../config/uiConfig';
import { CustomSnackBarContext } from '../../contexts/CustomSnackBarContext';
import greyPattern from '@assets/grey-pattern.png';
import { isArray } from 'lodash';
+import { useTranslation } from 'react-i18next';
interface BaseFileInputComponentProps extends BaseFileInputProps {
children: (props: { preview: string | undefined }) => ReactNode;
@@ -26,6 +27,7 @@ export default function BaseFileInput({
children,
type
}: BaseFileInputComponentProps) {
+ const { t } = useTranslation();
const [preview, setPreview] = useState(null);
const [isDragging, setIsDragging] = useState(false);
const theme = useTheme();
@@ -60,9 +62,9 @@ export default function BaseFileInput({
navigator.clipboard
.write([clipboardItem])
- .then(() => showSnackBar('File copied', 'success'))
+ .then(() => showSnackBar(t('baseFileInput.fileCopied'), 'success'))
.catch((err) => {
- showSnackBar('Failed to copy: ' + err, 'error');
+ showSnackBar(t('baseFileInput.copyFailed', { error: err }), 'error');
});
}
};
@@ -190,7 +192,7 @@ export default function BaseFileInput({
variant="h6"
align="center"
>
- Drop your {type} here
+ {t('baseFileInput.dropFileHere', { type })}
) : (
- Click here to select a {type} from your device, press Ctrl+V to
- use a {type} from your clipboard, or drag and drop a file from
- desktop
+ {t('baseFileInput.selectFileDescription', { type })}
)}
diff --git a/src/components/input/InputFooter.tsx b/src/components/input/InputFooter.tsx
index 5760022..3a4afa5 100644
--- a/src/components/input/InputFooter.tsx
+++ b/src/components/input/InputFooter.tsx
@@ -3,6 +3,7 @@ import Button from '@mui/material/Button';
import PublishIcon from '@mui/icons-material/Publish';
import ContentPasteIcon from '@mui/icons-material/ContentPaste';
import ClearIcon from '@mui/icons-material/Clear';
+import { useTranslation } from 'react-i18next';
export default function InputFooter({
handleImport,
@@ -13,19 +14,21 @@ export default function InputFooter({
handleCopy?: () => void;
handleClear?: () => void;
}) {
+ const { t } = useTranslation();
+
return (
}>
- Import from file
+ {t('inputFooter.importFromFile')}
{handleCopy && (
}>
- Copy to clipboard
+ {t('inputFooter.copyToClipboard')}
)}
{handleClear && (
}>
- Clear
+ {t('inputFooter.clear')}
)}
diff --git a/src/components/input/NumericInputWithUnit.tsx b/src/components/input/NumericInputWithUnit.tsx
index a545685..436d933 100644
--- a/src/components/input/NumericInputWithUnit.tsx
+++ b/src/components/input/NumericInputWithUnit.tsx
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { Grid, Select, MenuItem } from '@mui/material';
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
import Qty from 'js-quantities';
+import { useTranslation } from 'react-i18next';
//
const siPrefixes: { [key: string]: number } = {
@@ -23,6 +24,7 @@ export default function NumericInputWithUnit(props: {
onOwnChange?: (value: { value: number; unit: string }) => void;
defaultPrefix?: string;
}) {
+ const { t } = useTranslation();
const [inputValue, setInputValue] = useState(props.value.value);
const [prefix, setPrefix] = useState(props.defaultPrefix || 'Default prefix');
@@ -158,7 +160,7 @@ export default function NumericInputWithUnit(props: {