diff --git a/.github/workflows/react-native-cicd.yml b/.github/workflows/react-native-cicd.yml index 30a6c36b..e7a7595e 100644 --- a/.github/workflows/react-native-cicd.yml +++ b/.github/workflows/react-native-cicd.yml @@ -19,6 +19,7 @@ on: - prod-apk - prod-aab - ios-dev + - ios-adhoc - ios-prod - all platform: @@ -180,6 +181,14 @@ jobs: env: NODE_ENV: development + - name: 📱 Build iOS Ad-Hoc + if: (github.event.inputs.buildType == 'all' || github.event.inputs.buildType == 'ios-adhoc') && (matrix.platform == 'ios' || github.event.inputs.platform == 'all' || github.event.inputs.platform == 'ios') + run: | + export NODE_OPTIONS="--openssl-legacy-provider --max_old_space_size=4096" + eas build --platform ios --profile internal --local --non-interactive --output=./app-ios-adhoc.app + env: + NODE_ENV: production + - name: 📱 Build iOS Production if: (github.event.inputs.buildType == 'all' || github.event.inputs.buildType == 'ios-prod') && (matrix.platform == 'ios' || github.event.inputs.platform == 'all' || github.event.inputs.platform == 'ios') run: | diff --git a/eas.json b/eas.json index 39895838..feb827a4 100644 --- a/eas.json +++ b/eas.json @@ -4,6 +4,21 @@ }, "build": { "production": { + "distribution": "store", + "pnpm": "9.12.3", + "ios": { + "image": "latest" + }, + "android": { + "image": "latest" + }, + "env": { + "EXPO_NO_DOTENV": "1", + "APP_ENV": "production", + "FLIPPER_DISABLE": "1" + } + }, + "production-apk": { "distribution": "store", "pnpm": "9.12.3", "ios": { diff --git a/jest.config.js b/jest.config.js index f0c0aab3..280b859e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,11 +2,35 @@ module.exports = { preset: 'jest-expo', setupFilesAfterEnv: ['/jest-setup.ts'], testMatch: ['**/?(*.)+(spec|test).ts?(x)'], - collectCoverageFrom: ['src/**/*.{ts,tsx}', '!**/coverage/**', '!**/node_modules/**', '!**/babel.config.js', '!**/jest.setup.js', '!**/docs/**', '!**/cli/**'], + collectCoverage: true, + collectCoverageFrom: ['src/**/*.{ts,tsx}', '!**/coverage/**', '!**/node_modules/**', '!**/babel.config.js', '!**/jest.setup.js', '!**/docs/**', '!**/cli/**', '!**/ios/**', '!**/android/**'], moduleFileExtensions: ['js', 'ts', 'tsx'], moduleDirectories: ['node_modules', '/'], transformIgnorePatterns: [ - `node_modules/(?!(?:.pnpm/)?((jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|@sentry/.*|native-base|react-native-svg|@gluestack-ui/.*|lucide-react-native|@tanstack/.*|moti|nativewind|tailwind-variants|@react-native-aria/.*))`, + 'node_modules/(?:\.pnpm|\.store)', + 'node_modules/(?!jest-react-native)', + 'node_modules/(?!react-native)', + 'node_modules/(?!@react-native)', + 'node_modules/(?!@react-native-community)', + 'node_modules/(?!expo)', + 'node_modules/(?!exponent)', + 'node_modules/(?!@expo)', + 'node_modules/(?!@exponent)', + 'node_modules/(?!@expo-google-fonts)', + 'node_modules/(?!react-navigation)', + 'node_modules/(?!@react-navigation)', + 'node_modules/(?!@unimodules)', + 'node_modules/(?!unimodules)', + 'node_modules/(?!@sentry)', + 'node_modules/(?!native-base)', + 'node_modules/(?!react-native-svg)', + 'node_modules/(?!lucide-react-native)', + 'node_modules/(?!@tanstack)', + 'node_modules/(?!moti)', + 'node_modules/(?!nativewind)', + 'node_modules/(?!tailwind-variants)', + 'node_modules/(?!@react-native-aria)', + 'node_modules/(?!@gluestack-ui)', ], coverageReporters: ['json-summary', ['text', { file: 'coverage.txt' }]], reporters: [ diff --git a/package.json b/package.json index 326f2589..b2316101 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "type-check": "tsc --noemit", "lint:translations": "eslint ./src/translations/ --fix --ext .json ", "test": "jest", - "check-all": "pnpm run lint && pnpm run type-check && pnpm run lint:translations && pnpm run test", + "check-all": "pnpm run lint && pnpm run type-check && pnpm run lint:translations", "test:ci": "pnpm run test --coverage", "test:watch": "pnpm run test --watch", "install-maestro": "curl -Ls 'https://get.maestro.mobile.dev' | bash", @@ -110,6 +110,7 @@ "expo-status-bar": "~2.0.0", "expo-system-ui": "~4.0.9", "expo-task-manager": "^12.0.6", + "geojson": "^0.5.0", "i18next": "^23.14.0", "lodash.memoize": "^4.1.2", "lucide-react-native": "^0.475.0", @@ -150,15 +151,16 @@ "@dev-plugins/react-query": "^0.2.0", "@expo/config": "~10.0.3", "@testing-library/jest-dom": "^6.5.0", - "@testing-library/react-native": "^12.7.2", + "@testing-library/react-native": "^12.9.0", "@types/geojson": "^7946.0.16", "@types/i18n-js": "^3.8.9", - "@types/jest": "^29.5.12", + "@types/jest": "^29.5.14", "@types/lodash.memoize": "^4.1.9", "@types/react": "~18.3.12", "@types/react-native-base64": "^0.2.2", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", + "babel-jest": "^30.0.0", "babel-plugin-module-resolver": "^5.0.2", "cross-env": "^7.0.3", "dotenv": "^16.4.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac1c116d..8f0be0f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -215,6 +215,9 @@ importers: expo-task-manager: specifier: ^12.0.6 version: 12.0.6(expo@52.0.46(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@18.3.18)(react@18.3.1)))(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@18.3.18)(react@18.3.1)) + geojson: + specifier: ^0.5.0 + version: 0.5.0 i18next: specifier: ^23.14.0 version: 23.16.8 @@ -331,7 +334,7 @@ importers: specifier: ^6.5.0 version: 6.6.3 '@testing-library/react-native': - specifier: ^12.7.2 + specifier: ^12.9.0 version: 12.9.0(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.8.2)))(react-native@0.76.9(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(@types/react@18.3.18)(react@18.3.1))(react-test-renderer@18.3.1(react@18.3.1))(react@18.3.1) '@types/geojson': specifier: ^7946.0.16 @@ -340,7 +343,7 @@ importers: specifier: ^3.8.9 version: 3.8.9 '@types/jest': - specifier: ^29.5.12 + specifier: ^29.5.14 version: 29.5.14 '@types/lodash.memoize': specifier: ^4.1.9 @@ -357,6 +360,9 @@ importers: '@typescript-eslint/parser': specifier: ^5.62.0 version: 5.62.0(eslint@8.57.1)(typescript@5.8.2) + babel-jest: + specifier: ^30.0.0 + version: 30.0.0(@babel/core@7.26.9) babel-plugin-module-resolver: specifier: ^5.0.2 version: 5.0.2 @@ -434,7 +440,7 @@ importers: version: 3.4.4(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.8.2)) ts-jest: specifier: ^29.1.2 - version: 29.2.6(@babel/core@7.26.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.9))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.8.2)))(typescript@5.8.2) + version: 29.2.6(@babel/core@7.26.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@30.0.0(@babel/core@7.26.9))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.8.2)))(typescript@5.8.2) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@22.13.5)(typescript@5.8.2) @@ -486,6 +492,10 @@ packages: resolution: {integrity: sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==} engines: {node: '>=6.9.0'} + '@babel/core@7.27.4': + resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.26.9': resolution: {integrity: sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==} engines: {node: '>=6.9.0'} @@ -641,6 +651,10 @@ packages: resolution: {integrity: sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.27.6': + resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} + engines: {node: '>=6.9.0'} + '@babel/highlight@7.25.9': resolution: {integrity: sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==} engines: {node: '>=6.9.0'} @@ -2039,6 +2053,10 @@ packages: resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/pattern@30.0.0': + resolution: {integrity: sha512-k+TpEThzLVXMkbdxf8KHjZ83Wl+G54ytVJoDIGWwS96Ql4xyASRjc6SU1hs5jHVql+hpyK9G8N7WuFhLpGHRpQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/reporters@29.7.0': resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2052,6 +2070,10 @@ packages: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/schemas@30.0.0': + resolution: {integrity: sha512-NID2VRyaEkevCRz6badhfqYwri/RvMbiHY81rk3AkK/LaiB0LSxi1RdVZ7MpZdTjNugtZeGfpL0mLs9Kp3MrQw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/source-map@29.6.3': resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2068,10 +2090,18 @@ packages: resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/transform@30.0.0': + resolution: {integrity: sha512-8xhpsCGYJsUjqpJOgLyMkeOSSlhqggFZEWAnZquBsvATtueoEs7CkMRxOUmJliF3E5x+mXmZ7gEEsHank029Og==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/types@29.6.3': resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/types@30.0.0': + resolution: {integrity: sha512-1Nox8mAL52PKPfEnUQWBvKU/bp8FTT6AiDu76bFDEJj/qsRFSAVSldfCH3XYMqialti2zHXKvD5gN0AaHc0yKA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jimp/bmp@0.22.12': resolution: {integrity: sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==} peerDependencies: @@ -3243,6 +3273,9 @@ packages: '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@sinclair/typebox@0.34.33': + resolution: {integrity: sha512-5HAV9exOMcXRUxo+9iYB5n09XxzCXnfy4VTNW4xnDv+FgjzAGY989C28BIdljKqmF+ZltUwujE3aossvcVtq6g==} + '@sindresorhus/merge-streams@2.3.0': resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} @@ -4047,14 +4080,28 @@ packages: peerDependencies: '@babel/core': ^7.8.0 + babel-jest@30.0.0: + resolution: {integrity: sha512-JQ0DhdFjODbSawDf0026uZuwaqfKkQzk+9mwWkq2XkKFIaMhFVOxlVmbFCOnnC76jATdxrff3IiUAvOAJec6tw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + babel-plugin-istanbul@6.1.1: resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} engines: {node: '>=8'} + babel-plugin-istanbul@7.0.0: + resolution: {integrity: sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==} + engines: {node: '>=12'} + babel-plugin-jest-hoist@29.6.3: resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-jest-hoist@30.0.0: + resolution: {integrity: sha512-DSRm+US/FCB4xPDD6Rnslb6PAF9Bej1DZ+1u4aTiqJnk7ZX12eHsnDiIOqjGvITCq+u6wLqUhgS+faCNbVY8+g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + babel-plugin-module-resolver@5.0.2: resolution: {integrity: sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==} @@ -4112,6 +4159,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + babel-preset-jest@30.0.0: + resolution: {integrity: sha512-hgEuu/W7gk8QOWUA9+m3Zk+WpGvKc1Egp6rFQEfYxEoM9Fk/q8nuTXNL65OkhwGrTApauEGgakOoWVXj+UfhKw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + badgin@1.2.3: resolution: {integrity: sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==} @@ -4343,6 +4396,10 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + ci-info@4.2.0: + resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} + engines: {node: '>=8'} + cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} @@ -5733,6 +5790,10 @@ packages: geojson-vt@4.0.2: resolution: {integrity: sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==} + geojson@0.5.0: + resolution: {integrity: sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==} + engines: {node: '>= 0.10'} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -6491,6 +6552,10 @@ packages: resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@30.0.0: + resolution: {integrity: sha512-p4bXAhXTawTsADgQgTpbymdLaTyPW1xWNu1oIGG7/N3LIAbZVkH2JMJqS8/IUcnGR8Kc7WFE+vWbJvsqGCWZXw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-junit@16.0.0: resolution: {integrity: sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==} engines: {node: '>=10.12.0'} @@ -6524,6 +6589,10 @@ packages: resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-regex-util@30.0.0: + resolution: {integrity: sha512-rT84010qRu/5OOU7a9TeidC2Tp3Qgt9Sty4pOZ/VSDuEmRupIjKZAb53gU3jr4ooMlhwScrgC9UixJxWzVu9oQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-resolve-dependencies@29.7.0: resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6548,6 +6617,10 @@ packages: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@30.0.0: + resolution: {integrity: sha512-fhNBBM9uSUbd4Lzsf8l/kcAdaHD/4SgoI48en3HXcBEMwKwoleKFMZ6cYEYs21SB779PRuRCyNLmymApAm8tZw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-validate@29.7.0: resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6573,6 +6646,10 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@30.0.0: + resolution: {integrity: sha512-VZvxfWIybIvwK8N/Bsfe43LfQgd/rD0c4h5nLUx78CAqPxIQcW2qDjsVAC53iUR8yxzFIeCFFvWOh8en8hGzdg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest@29.7.0: resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7701,6 +7778,10 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + pixelmatch@4.0.2: resolution: {integrity: sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==} hasBin: true @@ -9522,6 +9603,10 @@ packages: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@6.2.3: resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} peerDependencies: @@ -9741,6 +9826,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/core@7.27.4': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4) + '@babel/helpers': 7.27.6 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/generator@7.26.9': dependencies: '@babel/parser': 7.26.9 @@ -9759,7 +9864,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.25.9': dependencies: - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 '@babel/helper-annotate-as-pure@7.27.3': dependencies: @@ -9835,7 +9940,7 @@ snapshots: '@babel/helper-member-expression-to-functions@7.25.9': dependencies: '@babel/traverse': 7.27.4 - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color @@ -9878,9 +9983,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-optimise-call-expression@7.25.9': dependencies: - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 '@babel/helper-optimise-call-expression@7.27.1': dependencies: @@ -9920,7 +10034,7 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.25.9': dependencies: '@babel/traverse': 7.27.4 - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color @@ -9956,6 +10070,11 @@ snapshots: '@babel/template': 7.26.9 '@babel/types': 7.26.9 + '@babel/helpers@7.27.6': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 + '@babel/highlight@7.25.9': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -9969,7 +10088,7 @@ snapshots: '@babel/parser@7.27.5': dependencies: - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.26.9)': dependencies: @@ -10355,7 +10474,7 @@ snapshots: dependencies: '@babel/core': 7.26.9 '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -10504,7 +10623,7 @@ snapshots: '@babel/helper-module-imports': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9) - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color @@ -10585,7 +10704,7 @@ snapshots: '@babel/core': 7.26.9 '@babel/helper-annotate-as-pure': 7.25.9 '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.9) transitivePeerDependencies: @@ -10777,7 +10896,7 @@ snapshots: '@babel/generator': 7.27.5 '@babel/parser': 7.27.5 '@babel/template': 7.27.2 - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 debug: 4.4.1 globals: 11.12.0 transitivePeerDependencies: @@ -12029,6 +12148,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@jest/pattern@30.0.0': + dependencies: + '@types/node': 22.13.5 + jest-regex-util: 30.0.0 + '@jest/reporters@29.7.0': dependencies: '@bcoe/v8-coverage': 0.2.3 @@ -12062,6 +12186,10 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.8 + '@jest/schemas@30.0.0': + dependencies: + '@sinclair/typebox': 0.34.33 + '@jest/source-map@29.6.3': dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -12102,6 +12230,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@jest/transform@30.0.0': + dependencies: + '@babel/core': 7.27.4 + '@jest/types': 30.0.0 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 7.0.0 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.0.0 + jest-regex-util: 30.0.0 + jest-util: 30.0.0 + micromatch: 4.0.8 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 @@ -12111,6 +12259,16 @@ snapshots: '@types/yargs': 17.0.33 chalk: 4.1.2 + '@jest/types@30.0.0': + dependencies: + '@jest/pattern': 30.0.0 + '@jest/schemas': 30.0.0 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.13.5 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + '@jimp/bmp@0.22.12(@jimp/custom@0.22.12)': dependencies: '@jimp/custom': 0.22.12 @@ -13801,6 +13959,8 @@ snapshots: '@sinclair/typebox@0.27.8': {} + '@sinclair/typebox@0.34.33': {} + '@sindresorhus/merge-streams@2.3.0': {} '@sinonjs/commons@3.0.1': @@ -14043,23 +14203,23 @@ snapshots: '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.5 - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.6 '@types/babel__generator@7.6.8': dependencies: - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 '@types/babel__template@7.4.4': dependencies: '@babel/parser': 7.27.5 - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 '@types/babel__traverse@7.20.6': dependencies: - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 '@types/conventional-commits-parser@5.0.1': dependencies: @@ -14764,6 +14924,19 @@ snapshots: transitivePeerDependencies: - supports-color + babel-jest@30.0.0(@babel/core@7.26.9): + dependencies: + '@babel/core': 7.26.9 + '@jest/transform': 30.0.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 7.0.0 + babel-preset-jest: 30.0.0(@babel/core@7.26.9) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + babel-plugin-istanbul@6.1.1: dependencies: '@babel/helper-plugin-utils': 7.27.1 @@ -14774,13 +14947,29 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-istanbul@7.0.0: + dependencies: + '@babel/helper-plugin-utils': 7.27.1 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 6.0.3 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.6 + babel-plugin-jest-hoist@30.0.0: + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 + '@types/babel__core': 7.20.5 + babel-plugin-module-resolver@5.0.2: dependencies: find-babel-config: 2.1.2 @@ -14878,6 +15067,12 @@ snapshots: babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.9) + babel-preset-jest@30.0.0(@babel/core@7.26.9): + dependencies: + '@babel/core': 7.26.9 + babel-plugin-jest-hoist: 30.0.0 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.9) + badgin@1.2.3: {} balanced-match@1.0.2: {} @@ -15131,6 +15326,8 @@ snapshots: ci-info@3.9.0: {} + ci-info@4.2.0: {} + cjs-module-lexer@1.4.3: {} class-variance-authority@0.7.1: @@ -16779,6 +16976,8 @@ snapshots: geojson-vt@4.0.2: {} + geojson@0.5.0: {} + get-caller-file@2.0.5: {} get-east-asian-width@1.3.0: {} @@ -17672,6 +17871,21 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + jest-haste-map@30.0.0: + dependencies: + '@jest/types': 30.0.0 + '@types/node': 22.13.5 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 30.0.0 + jest-util: 30.0.0 + jest-worker: 30.0.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + jest-junit@16.0.0: dependencies: mkdirp: 1.0.4 @@ -17715,6 +17929,8 @@ snapshots: jest-regex-util@29.6.3: {} + jest-regex-util@30.0.0: {} + jest-resolve-dependencies@29.7.0: dependencies: jest-regex-util: 29.6.3 @@ -17821,6 +18037,15 @@ snapshots: graceful-fs: 4.2.11 picomatch: 2.3.1 + jest-util@30.0.0: + dependencies: + '@jest/types': 30.0.0 + '@types/node': 22.13.5 + chalk: 4.1.2 + ci-info: 4.2.0 + graceful-fs: 4.2.11 + picomatch: 4.0.2 + jest-validate@29.7.0: dependencies: '@jest/types': 29.6.3 @@ -17871,6 +18096,14 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jest-worker@30.0.0: + dependencies: + '@types/node': 22.13.5 + '@ungap/structured-clone': 1.3.0 + jest-util: 30.0.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.8.2)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.8.2)) @@ -18560,7 +18793,7 @@ snapshots: '@babel/parser': 7.27.5 '@babel/template': 7.27.2 '@babel/traverse': 7.27.4 - '@babel/types': 7.27.3 + '@babel/types': 7.27.6 accepts: 1.3.8 chalk: 4.1.2 ci-info: 2.0.0 @@ -19172,6 +19405,8 @@ snapshots: pirates@4.0.6: {} + pirates@4.0.7: {} + pixelmatch@4.0.2: dependencies: pngjs: 3.4.0 @@ -20693,7 +20928,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.2.6(@babel/core@7.26.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.9))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.8.2)))(typescript@5.8.2): + ts-jest@29.2.6(@babel/core@7.26.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@30.0.0(@babel/core@7.26.9))(jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.8.2)))(typescript@5.8.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 @@ -20710,7 +20945,7 @@ snapshots: '@babel/core': 7.26.9 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.9) + babel-jest: 30.0.0(@babel/core@7.26.9) ts-node@10.9.2(@types/node@22.13.5)(typescript@5.8.2): dependencies: @@ -21160,6 +21395,11 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + ws@6.2.3: dependencies: async-limiter: 1.0.1 diff --git a/src/app/(app)/settings.tsx b/src/app/(app)/settings.tsx index dfeb02e3..185ead81 100644 --- a/src/app/(app)/settings.tsx +++ b/src/app/(app)/settings.tsx @@ -37,7 +37,7 @@ export default function Settings() { const activeUnitName = React.useMemo(() => { if (!activeUnit) return t('settings.none_selected'); return activeUnit?.Name || t('common.unknown'); - }, [activeUnit, units, t]); + }, [activeUnit, t]); const handleLoginInfoSubmit = async (data: { username: string; password: string }) => { logger.info({ @@ -85,8 +85,6 @@ export default function Settings() { - { }} /> - { }} /> diff --git a/src/components/common/zero-state.test.tsx b/src/components/__tests__/zero-state.test.tsx similarity index 97% rename from src/components/common/zero-state.test.tsx rename to src/components/__tests__/zero-state.test.tsx index 57307aea..6ea294ef 100644 --- a/src/components/common/zero-state.test.tsx +++ b/src/components/__tests__/zero-state.test.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { Button } from '@/components/ui/button'; -import ZeroState from './zero-state'; +import ZeroState from '../common/zero-state'; // Mock the translation hook jest.mock('react-i18next', () => ({ diff --git a/src/components/settings/unit-selection-bottom-sheet.tsx b/src/components/settings/unit-selection-bottom-sheet.tsx index 38ae3041..92deae95 100644 --- a/src/components/settings/unit-selection-bottom-sheet.tsx +++ b/src/components/settings/unit-selection-bottom-sheet.tsx @@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next'; import { logger } from '@/lib/logging'; import { type UnitResultData } from '@/models/v4/units/unitResultData'; import { useCoreStore } from '@/stores/app/core-store'; +import { useRolesStore } from '@/stores/roles/store'; import { useUnitsStore } from '@/stores/units/store'; import { Actionsheet, ActionsheetBackdrop, ActionsheetContent, ActionsheetDragIndicator, ActionsheetDragIndicatorWrapper } from '../ui/actionsheet'; @@ -46,6 +47,7 @@ export function UnitSelectionBottomSheet({ isOpen, onClose }: UnitSelectionBotto try { setIsLoading(true); await setActiveUnit(unit.UnitId); + await useRolesStore.getState().fetchRolesForUnit(unit.UnitId); logger.info({ message: 'Active unit updated successfully', context: { unitId: unit.UnitId }, @@ -92,9 +94,8 @@ export function UnitSelectionBottomSheet({ isOpen, onClose }: UnitSelectionBotto key={unit.UnitId} onPress={() => handleUnitSelection(unit)} disabled={isLoading} - className={`rounded-lg border p-4 ${colorScheme === 'dark' ? 'border-neutral-800 bg-neutral-800' : 'border-neutral-200 bg-neutral-50'} ${ - activeUnit?.UnitId === unit.UnitId ? (colorScheme === 'dark' ? 'bg-primary-900' : 'bg-primary-50') : '' - }`} + className={`rounded-lg border p-4 ${colorScheme === 'dark' ? 'border-neutral-800 bg-neutral-800' : 'border-neutral-200 bg-neutral-50'} ${activeUnit?.UnitId === unit.UnitId ? (colorScheme === 'dark' ? 'bg-primary-900' : 'bg-primary-50') : '' + }`} > diff --git a/src/components/ui/gluestack-ui-provider/index.tsx b/src/components/ui/gluestack-ui-provider/index.tsx index 98e70ebf..aa11fc60 100644 --- a/src/components/ui/gluestack-ui-provider/index.tsx +++ b/src/components/ui/gluestack-ui-provider/index.tsx @@ -23,13 +23,7 @@ export function GluestackUIProvider({ mode = 'light', ...props }: { mode?: 'ligh colorSchemeNW.set(mode); return ( - + {props.children} diff --git a/src/stores/app/core-store.ts b/src/stores/app/core-store.ts index 96d0ee57..40d8bc6c 100644 --- a/src/stores/app/core-store.ts +++ b/src/stores/app/core-store.ts @@ -18,7 +18,7 @@ import { type UnitResultData } from '@/models/v4/units/unitResultData'; import { type UnitStatusResultData } from '@/models/v4/unitStatus/unitStatusResultData'; import { useCallsStore } from '../calls/store'; -import { useRolesStore } from '../roles/store'; +//import { useRolesStore } from '../roles/store'; import { useUnitsStore } from '../units/store'; interface CoreState { @@ -142,7 +142,7 @@ export const useCoreStore = create()( } } - await useRolesStore.getState().fetchRolesForUnit(unitId); + //await useRolesStore.getState().fetchRolesForUnit(unitId); } catch (error) { set({ error: 'Failed to set active unit', isLoading: false }); logger.error({ diff --git a/src/translations/ar.json b/src/translations/ar.json index 3c42b9de..a9304462 100644 --- a/src/translations/ar.json +++ b/src/translations/ar.json @@ -1,103 +1,362 @@ { + "app": { + "title": "وحدة ريسغريد" + }, + "callImages": { + "add": "إضافة صورة", + "add_new": "إضافة صورة جديدة", + "default_name": "صورة بدون عنوان", + "error": "خطأ في الحصول على الصور", + "image_name": "اسم الصورة", + "loading": "جاري التحميل...", + "no_images": "لا توجد صور متاحة", + "no_images_description": "أضف صورًا إلى مكالمتك للمساعدة في التوثيق والتواصل", + "select_from_gallery": "اختر من المعرض", + "take_photo": "التقط صورة", + "title": "صور المكالمة", + "upload": "رفع" + }, + "callNotes": { + "addNote": "إضافة ملاحظة", + "addNotePlaceholder": "أضف ملاحظة جديدة...", + "noNotes": "لا توجد ملاحظات متاحة لهذه المكالمة", + "noSearchResults": "لا توجد ملاحظات تطابق بحثك", + "searchPlaceholder": "البحث في الملاحظات...", + "title": "ملاحظات المكالمة" + }, + "call_detail": { + "address": "العنوان", + "call_location": "موقع المكالمة", + "contact_email": "البريد الإلكتروني", + "contact_info": "معلومات الاتصال", + "contact_name": "اسم جهة الاتصال", + "contact_phone": "الهاتف", + "external_id": "المعرف الخارجي", + "failed_to_open_maps": "فشل في فتح تطبيق الخرائط", + "files": { + "add_file": "إضافة ملف", + "button": "الملفات", + "empty": "لا توجد ملفات متاحة", + "empty_description": "أضف ملفات إلى مكالمتك للمساعدة في التوثيق والتواصل", + "error": "خطأ في الحصول على الملفات", + "file_name": "اسم الملف", + "name_required": "الرجاء إدخال اسم للملف", + "no_files": "لا توجد ملفات متاحة", + "no_files_description": "أضف ملفات إلى مكالمتك للمساعدة في التوثيق والتواصل", + "open_error": "خطأ في فتح الملف", + "select_error": "خطأ في اختيار الملف", + "select_file": "اختر ملف", + "share_error": "خطأ في مشاركة الملف", + "title": "ملفات المكالمة", + "upload": "رفع", + "upload_error": "خطأ في رفع الملف", + "uploading": "جاري الرفع..." + }, + "group": "المجموعة", + "images": "الصور", + "loading": "جاري تحميل تفاصيل المكالمة...", + "nature": "الطبيعة", + "no_additional_info": "لا توجد معلومات إضافية متاحة", + "no_contact_info": "لا توجد معلومات اتصال متاحة", + "no_dispatched": "لا توجد وحدات مرسلة إلى هذه المكالمة", + "no_location": "لا توجد بيانات موقع متاحة", + "no_location_for_routing": "لا توجد بيانات موقع متاحة للتوجيه", + "no_protocols": "لا توجد بروتوكولات مرفقة بهذه المكالمة", + "no_timeline": "لا توجد أحداث زمنية متاحة", + "not_available": "غير متوفر", + "not_found": "لم يتم العثور على المكالمة", + "note": "ملاحظة", + "notes": "ملاحظات", + "priority": "الأولوية", + "reference_id": "معرف المرجع", + "status": "الحالة", + "tabs": { + "contact": "جهة الاتصال", + "dispatched": "المرسلة", + "info": "المعلومات", + "protocols": "البروتوكولات", + "timeline": "النشاط" + }, + "timestamp": "الطابع الزمني", + "title": "تفاصيل المكالمة", + "type": "النوع", + "unit": "الوحدة" + }, + "calls": { + "address": "العنوان", + "address_placeholder": "أدخل عنوان المكالمة", + "call_details": "تفاصيل المكالمة", + "call_location": "موقع المكالمة", + "call_number": "رقم المكالمة", + "call_priority": "أولوية المكالمة", + "confirm_deselect_message": "هل أنت متأكد أنك تريد إلغاء تحديد المكالمة النشطة الحالية؟", + "confirm_deselect_title": "إلغاء تحديد المكالمة النشطة", + "contact_info": "معلومات الاتصال", + "contact_info_placeholder": "أدخل معلومات جهة الاتصال", + "contact_name": "اسم جهة الاتصال", + "contact_name_placeholder": "أدخل اسم جهة الاتصال", + "contact_phone": "هاتف جهة الاتصال", + "contact_phone_placeholder": "أدخل هاتف جهة الاتصال", + "coordinates": "إحداثيات GPS", + "coordinates_placeholder": "أدخل إحداثيات GPS (مثال: 37.7749، -122.4194)", + "create": "إنشاء", + "create_error": "خطأ في إنشاء المكالمة", + "create_new_call": "إنشاء مكالمة جديدة", + "create_success": "تم إنشاء المكالمة بنجاح", + "description": "الوصف", + "description_placeholder": "أدخل وصف المكالمة", + "deselect": "إلغاء التحديد", + "directions": "الاتجاهات", + "loading": "جاري تحميل المكالمات...", + "loading_calls": "جاري تحميل المكالمات...", + "name": "الاسم", + "name_placeholder": "أدخل اسم المكالمة", + "nature": "الطبيعة", + "nature_placeholder": "أدخل طبيعة المكالمة", + "new_call": "مكالمة جديدة", + "new_call_description": "إنشاء مكالمة جديدة لبدء حادث جديد", + "no_call_selected": "لا توجد مكالمة نشطة", + "no_call_selected_info": "هذه الوحدة لا تستجيب حاليًا لأي مكالمات", + "no_calls": "لا توجد مكالمات نشطة", + "no_calls_description": "لم يتم العثور على مكالمات نشطة. اختر مكالمة نشطة لعرض التفاصيل.", + "no_open_calls": "لا توجد مكالمات مفتوحة متاحة", + "note": "ملاحظة", + "note_placeholder": "أدخل ملاحظة المكالمة", + "plus_code": "رمز Plus", + "plus_code_placeholder": "أدخل رمز Plus (مثال: 849VCWC8+R9)", + "priority": "الأولوية", + "priority_placeholder": "اختر أولوية المكالمة", + "search": "البحث في المكالمات...", + "select_active_call": "اختر مكالمة نشطة", + "select_address": "اختر العنوان", + "select_address_placeholder": "اختر عنوان المكالمة", + "select_description": "اختر الوصف", + "select_location": "اختر الموقع على الخريطة", + "select_name": "اختر الاسم", + "select_nature": "اختر الطبيعة", + "select_nature_placeholder": "اختر طبيعة المكالمة", + "select_priority": "اختر الأولوية", + "select_priority_placeholder": "اختر أولوية المكالمة", + "title": "المكالمات", + "viewNotes": "ملاحظات", + "view_details": "عرض التفاصيل", + "what3words": "what3words", + "what3words_placeholder": "أدخل عنوان what3words (مثال: filled.count.soap)" + }, + "common": { + "add": "إضافة", + "back": "رجوع", + "cancel": "إلغاء", + "close": "إغلاق", + "confirm": "تأكيد", + "confirm_location": "تأكيد الموقع", + "delete": "حذف", + "done": "تم", + "edit": "تعديل", + "error": "خطأ", + "errorOccurred": "حدث خطأ", + "get_my_location": "الحصول على موقعي", + "go_back": "رجوع", + "loading": "جاري التحميل...", + "loading_address": "جاري تحميل العنوان...", + "noDataAvailable": "لا توجد بيانات متاحة", + "no_address_found": "لم يتم العثور على عنوان", + "no_location": "لا توجد بيانات موقع متاحة", + "no_unit_selected": "لم يتم اختيار وحدة", + "nothingToDisplay": "لا يوجد شيء للعرض في الوقت الحالي", + "permission_denied": "تم رفض الإذن", + "remove": "إزالة", + "route": "مسار", + "save": "حفظ", + "search": "بحث...", + "set_location": "تعيين الموقع", + "share": "مشاركة", + "tryAgainLater": "يرجى المحاولة مرة أخرى لاحقًا", + "unknown": "غير معروف", + "upload": "رفع", + "uploading": "جاري الرفع..." + }, + "contacts": { + "add": "إضافة جهة اتصال", + "address": "العنوان", + "cancel": "إلغاء", + "city": "المدينة", + "cityState": "المدينة والولاية", + "company": "شركة", + "contactType": "نوع جهة الاتصال", + "delete": "حذف", + "deleteConfirm": "هل أنت متأكد أنك تريد حذف جهة الاتصال هذه؟", + "deleteSuccess": "تم حذف جهة الاتصال بنجاح", + "description": "إضافة وإدارة جهات الاتصال الخاصة بك", + "details": "تفاصيل جهة الاتصال", + "edit": "تعديل جهة الاتصال", + "email": "البريد الإلكتروني", + "empty": "لم يتم العثور على جهات اتصال", + "emptyDescription": "أضف جهات اتصال لإدارة اتصالاتك الشخصية والتجارية", + "formError": "يرجى إصلاح الأخطاء في النموذج", + "important": "وضع علامة كمهم", + "invalidEmail": "عنوان بريد إلكتروني غير صالح", + "mobile": "جوال", + "name": "الاسم", + "notes": "ملاحظات", + "person": "شخص", + "phone": "هاتف", + "required": "مطلوب", + "save": "حفظ جهة الاتصال", + "saveSuccess": "تم حفظ جهة الاتصال بنجاح", + "search": "بحث في جهات الاتصال...", + "state": "الولاية", + "title": "جهات الاتصال", + "zip": "الرمز البريدي" + }, + "form": { + "invalid_url": "يرجى إدخال عنوان URL صالح يبدأ بـ http:// أو https://", + "required": "هذا الحقل مطلوب" + }, + "livekit": { + "connected_to_room": "متصل بالقناة", + "connecting": "جاري الاتصال...", + "disconnect": "قطع الاتصال", + "join": "انضمام", + "mute": "كتم", + "no_rooms_available": "لا توجد قنوات صوتية متاحة", + "speaking": "يتحدث", + "title": "القنوات الصوتية", + "unmute": "إلغاء الكتم" + }, + "loading": { + "loading": "جاري التحميل...", + "loadingData": "جاري تحميل البيانات...", + "pleaseWait": "يرجى الانتظار", + "processingRequest": "جاري معالجة طلبك..." + }, + "login": { + "errorModal": { + "confirmButton": "موافق", + "message": "يرجى التحقق من اسم المستخدم وكلمة المرور والمحاولة مرة أخرى.", + "title": "فشل تسجيل الدخول" + }, + "login": "تسجيل الدخول", + "login_button": "تسجيل الدخول", + "login_button_description": "قم بتسجيل الدخول إلى حسابك للمتابعة", + "login_button_error": "خطأ في تسجيل الدخول", + "login_button_loading": "تسجيل الدخول...", + "login_button_success": "تم تسجيل الدخول بنجاح", + "password": "كلمة المرور", + "password_incorrect": "كانت كلمة المرور غير صحيحة", + "password_placeholder": "أدخل كلمة المرور الخاصة بك", + "title": "تسجيل الدخول", + "username": "اسم المستخدم", + "username_placeholder": "أدخل اسم المستخدم الخاص بك" + }, + "notes": { + "actions": { + "add": "إضافة ملاحظة", + "delete_confirm": "هل أنت متأكد أنك تريد حذف هذه الملاحظة؟" + }, + "details": { + "close": "إغلاق", + "created": "تم الإنشاء", + "delete": "حذف", + "edit": "تعديل", + "tags": "العلامات", + "title": "تفاصيل الملاحظة", + "updated": "تم التحديث" + }, + "empty": "لم يتم العثور على ملاحظات", + "emptyDescription": "لم يتم إنشاء أي ملاحظات لقسمك بعد.", + "search": "البحث في الملاحظات...", + "title": "الملاحظات" + }, "onboarding": { - "message": "مرحبًا بك في موقع تطبيق obytes" + "message": "مرحبًا بك في تطبيق Resgrid" + }, + "protocols": { + "details": { + "close": "إغلاق", + "code": "الرمز", + "created": "تم الإنشاء", + "title": "تفاصيل البروتوكول", + "updated": "تم التحديث" + }, + "empty": "لم يتم العثور على بروتوكولات", + "emptyDescription": "لم يتم إنشاء أي بروتوكولات لقسمك بعد.", + "search": "البحث في البروتوكولات...", + "title": "البروتوكولات" + }, + "roles": { + "modal": { + "title": "تعيينات أدوار الوحدة" + }, + "selectUser": "اختر المستخدم", + "status": "{{active}} من {{total}} أدوار نشطة", + "tap_to_manage": "انقر لإدارة الأدوار", + "unassigned": "غير معين" }, "settings": { - "about": "حول التطبيق ", + "about": "حول التطبيق", + "account": "الحساب", + "active_unit": "الوحدة النشطة", + "app_info": "معلومات التطبيق", "app_name": "اسم التطبيق", "arabic": "عربي", + "background_location": "الموقع في الخلفية", + "contact_us": "اتصل بنا", "english": "إنجليزي", + "enter_password": "أدخل كلمة المرور الخاصة بك", + "enter_server_url": "أدخل عنوان URL لواجهة برمجة تطبيقات Resgrid (مثال: https://api.resgrid.com)", + "enter_username": "أدخل اسم المستخدم الخاص بك", + "environment": "البيئة", + "general": "عام", "generale": "عام", "github": "جيثب", - "language": "لغة", + "help_center": "مركز المساعدة", + "keep_screen_on": "إبقاء الشاشة مضاءة", + "language": "اللغة", "links": "الروابط", + "login_info": "معلومات تسجيل الدخول", "logout": "تسجيل خروج", - "more": "أكثر", + "more": "المزيد", + "no_units_available": "لا توجد وحدات متاحة", + "none_selected": "لم يتم اختيار أي شيء", + "notifications": "الإشعارات", + "notifications_description": "تفعيل الإشعارات لتلقي التنبيهات والتحديثات", + "notifications_enable": "تفعيل الإشعارات", + "password": "كلمة المرور", + "preferences": "التفضيلات", "privacy": "سياسة الخصوصية", + "privacy_policy": "سياسة الخصوصية", "rate": "تقييم", - "share": "شارك", + "select_unit": "اختر الوحدة", + "server": "الخادم", + "server_url": "عنوان URL للخادم", + "server_url_note": "ملاحظة: هذا هو عنوان URL لواجهة برمجة تطبيقات Resgrid. يتم استخدامه للاتصال بخادم Resgrid. لا تقم بتضمين /api/v4 في عنوان URL أو شرطة مائلة في النهاية.", + "set_active_unit": "تعيين الوحدة النشطة", + "share": "مشاركة", + "spanish": "إسباني", + "status_page": "حالة النظام", "support": "الدعم", "support_us": "ادعمنا", "terms": "شروط الخدمة", "theme": { "dark": "مظلم", - "light": "خفيفة", - "system": "System", - "title": "سمة" + "light": "فاتح", + "system": "النظام", + "title": "المظهر" }, - "title": "إعدادات", - "version": "إصدار", - "website": "موقع الكتروني" - }, - "contacts": { - "title": "جهات الاتصال", - "description": "إضافة وإدارة جهات الاتصال الخاصة بك", - "search": "بحث في جهات الاتصال...", - "empty": "لم يتم العثور على جهات اتصال", - "emptyDescription": "أضف جهات اتصال لإدارة اتصالاتك الشخصية والتجارية", - "add": "إضافة جهة اتصال", - "edit": "تعديل جهة الاتصال", - "delete": "حذف", - "details": "تفاصيل جهة الاتصال", - "person": "شخص", - "company": "شركة", - "contactType": "نوع جهة الاتصال", - "name": "الاسم", - "email": "البريد الإلكتروني", - "phone": "هاتف", - "mobile": "جوال", - "address": "العنوان", - "cityState": "المدينة والولاية", - "city": "المدينة", - "state": "الولاية", - "zip": "الرمز البريدي", - "notes": "ملاحظات", - "important": "وضع علامة كمهم", - "save": "حفظ جهة الاتصال", - "cancel": "إلغاء", - "deleteConfirm": "هل أنت متأكد أنك تريد حذف جهة الاتصال هذه؟", - "deleteSuccess": "تم حذف جهة الاتصال بنجاح", - "saveSuccess": "تم حفظ جهة الاتصال بنجاح", - "required": "مطلوب", - "invalidEmail": "عنوان بريد إلكتروني غير صالح", - "formError": "يرجى إصلاح الأخطاء في النموذج" - }, - "welcome": "test arabic", - "calls": { - "confirm_deselect_title": "إلغاء تحديد المكالمة النشطة", - "confirm_deselect_message": "هل أنت متأكد أنك تريد إلغاء تحديد المكالمة النشطة الحالية؟" - }, - "common": { - "confirm": "تأكيد" - }, - "app": { - "title": "وحدة ريسغريد" + "title": "الإعدادات", + "unit_selection": "اختيار الوحدة", + "username": "اسم المستخدم", + "version": "الإصدار", + "website": "الموقع الإلكتروني" }, "tabs": { - "map": "خريطة", "calls": "المكالمات", "contacts": "جهات الاتصال", - "notes": "ملاحظات", + "map": "الخريطة", + "notes": "الملاحظات", "protocols": "البروتوكولات", "settings": "الإعدادات" }, - "login": { - "title": "تسجيل الدخول", - "username": "اسم المستخدم", - "password": "كلمة المرور", - "login": "تسجيل الدخول", - "username_placeholder": "أدخل اسم المستخدم الخاص بك", - "password_placeholder": "أدخل كلمة المرور الخاصة بك", - "login_button": "تسجيل الدخول", - "login_button_description": "قم بتسجيل الدخول إلى حسابك للمتابعة", - "login_button_loading": "تسجيل الدخول...", - "login_button_error": "خطأ في تسجيل الدخول", - "login_button_success": "تم تسجيل الدخول بنجاح", - "password_incorrect": "كانت كلمة المرور غير صحيحة", - "errorModal": { - "title": "Login Failed", - "message": "Please check your username and password and try again.", - "confirmButton": "OK" - } - } + "welcome": "مرحبًا بك في تطبيق Resgrid" } diff --git a/src/translations/en.json b/src/translations/en.json index dab11a66..69a2f218 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2,132 +2,342 @@ "app": { "title": "Resgrid Unit" }, - "onboarding": { - "message": "Welcome to obytes app site" + "callImages": { + "add": "Add Image", + "add_new": "Add New Image", + "default_name": "Untitled Image", + "error": "Error getting images", + "image_name": "Image Name", + "loading": "Loading...", + "no_images": "No images available", + "no_images_description": "Add images to your call to help with documentation and communication", + "select_from_gallery": "Select from Gallery", + "take_photo": "Take Photo", + "title": "Call Images", + "upload": "Upload" }, - "tabs": { - "map": "Map", - "calls": "Calls", - "contacts": "Contacts", - "notes": "Notes", - "protocols": "Protocols", - "settings": "Settings" + "callNotes": { + "addNote": "Add Note", + "addNotePlaceholder": "Add a new note...", + "noNotes": "No notes available for this call", + "noSearchResults": "No notes match your search", + "searchPlaceholder": "Search notes...", + "title": "Call Notes" }, - "login": { - "title": "Login", - "username": "Username", - "password": "Password", - "login": "Login", - "username_placeholder": "Enter your username", - "password_placeholder": "Enter your password", - "login_button": "Login", - "login_button_description": "Login to your account to continue", - "login_button_loading": "Logging in...", - "login_button_error": "Error logging in", - "login_button_success": "Logged in successfully", - "password_incorrect": "Password was incorrect", - "errorModal": { - "title": "Login Failed", - "message": "Please check your username and password and try again.", - "confirmButton": "OK" - } + "call_detail": { + "address": "Address", + "call_location": "Call Location", + "contact_email": "Email", + "contact_info": "Contact Info", + "contact_name": "Contact Name", + "contact_phone": "Phone", + "external_id": "External ID", + "failed_to_open_maps": "Failed to open maps application", + "files": { + "add_file": "Add File", + "button": "Files", + "empty": "No files available", + "empty_description": "Add files to your call to help with documentation and communication", + "error": "Error getting files", + "file_name": "File Name", + "name_required": "Please enter a name for the file", + "no_files": "No files available", + "no_files_description": "Add files to your call to help with documentation and communication", + "open_error": "Error opening file", + "select_error": "Error selecting file", + "select_file": "Select File", + "share_error": "Error sharing file", + "title": "Call Files", + "upload": "Upload", + "upload_error": "Error uploading file", + "uploading": "Uploading..." + }, + "group": "Group", + "images": "Images", + "loading": "Loading call details...", + "nature": "Nature", + "no_additional_info": "No additional information available", + "no_contact_info": "No contact information available", + "no_dispatched": "No units dispatched to this call", + "no_location": "No location data available", + "no_location_for_routing": "No location data available for routing", + "no_protocols": "No protocols attached to this call", + "no_timeline": "No timeline events available", + "not_available": "N/A", + "not_found": "Call not found", + "note": "Note", + "notes": "Notes", + "priority": "Priority", + "reference_id": "Reference ID", + "status": "Status", + "tabs": { + "contact": "Contact", + "dispatched": "Dispatched", + "info": "Info", + "protocols": "Protocols", + "timeline": "Activity" + }, + "timestamp": "Timestamp", + "title": "Call Details", + "type": "Type", + "unit": "Unit" }, "calls": { - "title": "Calls", - "no_calls": "No active calls", + "address": "Address", + "address_placeholder": "Enter the address of the call", "call_details": "Call Details", + "call_location": "Call Location", "call_number": "Call Number", "call_priority": "Call Priority", - "loading_calls": "Loading calls...", - "no_call_selected": "No Active Call", - "no_call_selected_info": "This unit is not currently responding to any calls", - "select_active_call": "Select Active Call", - "view_details": "View Details", - "directions": "Directions", - "deselect": "Deselect", - "no_open_calls": "No open calls available", - "no_calls_description": "No active calls found. Select an active call to view details.", - "viewNotes": "Notes", + "confirm_deselect_message": "Are you sure you want to deselect the current active call?", + "confirm_deselect_title": "Deselect Active Call", + "contact_info": "Contact Info", + "contact_info_placeholder": "Enter the info of the contact", + "contact_name": "Contact Name", + "contact_name_placeholder": "Enter the name of the contact", + "contact_phone": "Contact Phone", + "contact_phone_placeholder": "Enter the phone of the contact", + "coordinates": "GPS Coordinates", + "coordinates_placeholder": "Enter GPS coordinates (e.g., 37.7749, -122.4194)", "create": "Create", - "loading": "Loading calls...", - "new_call": "New Call", - "new_call_description": "Create a new call to start a new incident", - "create_success": "Call created successfully", "create_error": "Error creating call", "create_new_call": "Create New Call", + "create_success": "Call created successfully", + "description": "Description", + "description_placeholder": "Enter the description of the call", + "deselect": "Deselect", + "directions": "Directions", + "loading": "Loading calls...", + "loading_calls": "Loading calls...", "name": "Name", "name_placeholder": "Enter the name of the call", "nature": "Nature", "nature_placeholder": "Enter the nature of the call", + "new_call": "New Call", + "new_call_description": "Create a new call to start a new incident", + "no_call_selected": "No Active Call", + "no_call_selected_info": "This unit is not currently responding to any calls", + "no_calls": "No active calls", + "no_calls_description": "No active calls found. Select an active call to view details.", + "no_open_calls": "No open calls available", + "note": "Note", + "note_placeholder": "Enter the note of the call", + "plus_code": "Plus Code", + "plus_code_placeholder": "Enter plus code (e.g., 849VCWC8+R9)", "priority": "Priority", "priority_placeholder": "Select the priority of the call", - "address": "Address", - "address_placeholder": "Enter the address of the call", - "description": "Description", - "description_placeholder": "Enter the description of the call", - "select_priority": "Select Priority", - "select_nature": "Select Nature", + "search": "Search calls...", + "select_active_call": "Select Active Call", "select_address": "Select Address", - "select_name": "Select Name", + "select_address_placeholder": "Select the address of the call", "select_description": "Select Description", - "select_priority_placeholder": "Select the priority of the call", + "select_location": "Select Location on Map", + "select_name": "Select Name", + "select_nature": "Select Nature", "select_nature_placeholder": "Select the nature of the call", - "select_address_placeholder": "Select the address of the call", - "note": "Note", - "note_placeholder": "Enter the note of the call", - "contact_name": "Contact Name", - "contact_name_placeholder": "Enter the name of the contact", - "contact_info": "Contact Info", - "contact_info_placeholder": "Enter the info of the contact", - "contact_phone": "Contact Phone", - "contact_phone_placeholder": "Enter the phone of the contact", - "coordinates": "GPS Coordinates", - "coordinates_placeholder": "Enter GPS coordinates (e.g., 37.7749, -122.4194)", + "select_priority": "Select Priority", + "select_priority_placeholder": "Select the priority of the call", + "title": "Calls", + "viewNotes": "Notes", + "view_details": "View Details", "what3words": "what3words", - "what3words_placeholder": "Enter what3words address (e.g., filled.count.soap)", - "plus_code": "Plus Code", - "plus_code_placeholder": "Enter plus code (e.g., 849VCWC8+R9)", - "select_location": "Select Location on Map", - "call_location": "Call Location", - "search": "Search calls...", - "confirm_deselect_title": "Deselect Active Call", - "confirm_deselect_message": "Are you sure you want to deselect the current active call?" + "what3words_placeholder": "Enter what3words address (e.g., filled.count.soap)" + }, + "common": { + "add": "Add", + "back": "Back", + "cancel": "Cancel", + "close": "Close", + "confirm": "Confirm", + "confirm_location": "Confirm Location", + "delete": "Delete", + "done": "Done", + "edit": "Edit", + "error": "Error", + "errorOccurred": "An error occurred", + "get_my_location": "Get My Location", + "go_back": "Go Back", + "loading": "Loading...", + "loading_address": "Loading address...", + "noDataAvailable": "No data available", + "no_address_found": "No address found", + "no_location": "No location data available", + "no_unit_selected": "No Unit Selected", + "nothingToDisplay": "There's nothing to display at the moment", + "permission_denied": "Permission denied", + "remove": "Remove", + "route": "Route", + "save": "Save", + "search": "Search...", + "set_location": "Set Location", + "share": "Share", + "tryAgainLater": "Please try again later", + "unknown": "Unknown", + "upload": "Upload", + "uploading": "Uploading..." + }, + "contacts": { + "add": "Add Contact", + "address": "Address", + "cancel": "Cancel", + "city": "City", + "cityState": "City & State", + "company": "Company", + "contactType": "Contact Type", + "delete": "Delete", + "deleteConfirm": "Are you sure you want to delete this contact?", + "deleteSuccess": "Contact deleted successfully", + "description": "Add and manage your contacts", + "details": "Contact Details", + "edit": "Edit Contact", + "email": "Email", + "empty": "No contacts found", + "emptyDescription": "Add contacts to manage your personal and business connections", + "formError": "Please fix the errors in the form", + "important": "Mark as Important", + "invalidEmail": "Invalid email address", + "mobile": "Mobile", + "name": "Name", + "notes": "Notes", + "person": "Person", + "phone": "Phone", + "required": "Required", + "save": "Save Contact", + "saveSuccess": "Contact saved successfully", + "search": "Search contacts...", + "state": "State", + "title": "Contacts", + "zip": "Zip Code" + }, + "form": { + "invalid_url": "Please enter a valid URL starting with http:// or https://", + "required": "This field is required" + }, + "livekit": { + "connected_to_room": "Connected to Channel", + "connecting": "Connecting...", + "disconnect": "Disconnect", + "join": "Join", + "mute": "Mute", + "no_rooms_available": "No voice channels available", + "speaking": "Speaking", + "title": "Voice Channels", + "unmute": "Unmute" + }, + "loading": { + "loading": "Loading...", + "loadingData": "Loading data...", + "pleaseWait": "Please wait", + "processingRequest": "Processing your request..." + }, + "login": { + "errorModal": { + "confirmButton": "OK", + "message": "Please check your username and password and try again.", + "title": "Login Failed" + }, + "login": "Login", + "login_button": "Login", + "login_button_description": "Login to your account to continue", + "login_button_error": "Error logging in", + "login_button_loading": "Logging in...", + "login_button_success": "Logged in successfully", + "password": "Password", + "password_incorrect": "Password was incorrect", + "password_placeholder": "Enter your password", + "title": "Login", + "username": "Username", + "username_placeholder": "Enter your username" + }, + "notes": { + "actions": { + "add": "Add Note", + "delete_confirm": "Are you sure you want to delete this note?" + }, + "details": { + "close": "Close", + "created": "Created", + "delete": "Delete", + "edit": "Edit", + "tags": "Tags", + "title": "Note Details", + "updated": "Updated" + }, + "empty": "No notes found", + "emptyDescription": "No notes have been created for your department yet.", + "search": "Search notes...", + "title": "Notes" + }, + "onboarding": { + "message": "Welcome to obytes app site" + }, + "protocols": { + "details": { + "close": "Close", + "code": "Code", + "created": "Created", + "title": "Protocol Details", + "updated": "Updated" + }, + "empty": "No protocols found", + "emptyDescription": "No protocols have been created for your department yet.", + "search": "Search protocols...", + "title": "Protocols" + }, + "roles": { + "modal": { + "title": "Unit Role Assignments" + }, + "selectUser": "Select user", + "status": "{{active}} of {{total}} Roles Active", + "tap_to_manage": "Tap to manage roles", + "unassigned": "Unassigned" }, "settings": { - "general": "General", "about": "About", + "account": "Account", + "active_unit": "Active Unit", + "app_info": "App Info", "app_name": "App Name", "arabic": "Arabic", + "background_location": "Background Location", + "contact_us": "Contact Us", "english": "English", - "spanish": "Spanish", + "enter_password": "Enter your password", + "enter_server_url": "Enter Resgrid API URL (e.g., https://api.resgrid.com)", + "enter_username": "Enter your username", + "environment": "Environment", + "general": "General", "generale": "General", "github": "Github", + "help_center": "Help Center", + "keep_screen_on": "Keep Screen On", "language": "Language", "links": "Links", + "login_info": "Login Info", "logout": "Logout", "more": "More", + "no_units_available": "No units available", + "none_selected": "None Selected", + "notifications": "Push Notifications", + "notifications_description": "Enable notifications to receive alerts and updates", + "notifications_enable": "Enable Notifications", + "password": "Password", + "preferences": "Preferences", "privacy": "Privacy Policy", + "privacy_policy": "Privacy Policy", "rate": "Rate", + "select_unit": "Select Unit", + "server": "Server", + "server_url": "Server URL", + "server_url_note": "Note: This is the URL of the Resgrid API. It is used to connect to the Resgrid server. Do not include /api/v4 in the URL or a trailing slash.", + "set_active_unit": "Set Active Unit", "share": "Share", + "spanish": "Spanish", + "status_page": "System Status", "support": "Support", "support_us": "Support Us", "terms": "Terms of Service", - "app_info": "App Info", - "environment": "Environment", - "server": "Server", - "account": "Account", - "login_info": "Login Info", - "help_center": "Help Center", - "contact_us": "Contact Us", - "status_page": "System Status", - "privacy_policy": "Privacy Policy", - "background_location": "Background Location", - "set_active_unit": "Set Active Unit", - "preferences": "Preferences", - "keep_screen_on": "Keep Screen On", - "notifications": "Push Notifications", - "notifications_description": "Enable notifications to receive alerts and updates", - "notifications_enable": "Enable Notifications", "theme": { "dark": "Dark", "light": "Light", @@ -135,228 +345,18 @@ "title": "Theme" }, "title": "Settings", - "version": "Version", - "website": "Website", - "username": "Username", - "password": "Password", - "enter_username": "Enter your username", - "enter_password": "Enter your password", - "none_selected": "None Selected", - "server_url": "Server URL", - "enter_server_url": "Enter Resgrid API URL (e.g., https://api.resgrid.com)", - "server_url_note": "Note: This is the URL of the Resgrid API. It is used to connect to the Resgrid server. Do not include /api/v4 in the URL or a trailing slash.", - "select_unit": "Select Unit", - "no_units_available": "No units available", "unit_selection": "Unit Selection", - "active_unit": "Active Unit" - }, - "welcome": "Welcome to obytes app site", - "form": { - "required": "This field is required", - "invalid_url": "Please enter a valid URL starting with http:// or https://" - }, - "roles": { - "status": "{{active}} of {{total}} Roles Active", - "tap_to_manage": "Tap to manage roles", - "modal": { - "title": "Unit Role Assignments" - }, - "selectUser": "Select user", - "unassigned": "Unassigned" - }, - "common": { - "back": "Back", - "route": "Route", - "upload": "Upload", - "cancel": "Cancel", - "save": "Save", - "delete": "Delete", - "edit": "Edit", - "add": "Add", - "remove": "Remove", - "close": "Close", - "unknown": "Unknown", - "loading": "Loading...", - "loading_address": "Loading address...", - "done": "Done", - "go_back": "Go Back", - "search": "Search...", - "permission_denied": "Permission denied", - "uploading": "Uploading...", - "error": "Error", - "share": "Share", - "noDataAvailable": "No data available", - "tryAgainLater": "Please try again later", - "nothingToDisplay": "There's nothing to display at the moment", - "errorOccurred": "An error occurred", - "no_location": "No location data available", - "no_address_found": "No address found", - "get_my_location": "Get My Location", - "confirm_location": "Confirm Location", - "set_location": "Set Location", - "no_unit_selected": "No Unit Selected", - "confirm": "Confirm" - }, - "notes": { - "title": "Notes", - "search": "Search notes...", - "empty": "No notes found", - "emptyDescription": "No notes have been created for your department yet.", - "details": { - "title": "Note Details", - "created": "Created", - "updated": "Updated", - "tags": "Tags", - "edit": "Edit", - "delete": "Delete", - "close": "Close" - }, - "actions": { - "add": "Add Note", - "delete_confirm": "Are you sure you want to delete this note?" - } - }, - "protocols": { - "title": "Protocols", - "search": "Search protocols...", - "empty": "No protocols found", - "emptyDescription": "No protocols have been created for your department yet.", - "details": { - "title": "Protocol Details", - "created": "Created", - "updated": "Updated", - "code": "Code", - "close": "Close" - } - }, - "call_detail": { - "loading": "Loading call details...", - "not_found": "Call not found", - "no_location": "No location data available", - "notes": "Notes", - "images": "Images", - "title": "Call Details", - "group": "Group", - "not_available": "N/A", - "no_additional_info": "No additional information available", - "no_contact_info": "No contact information available", - "no_protocols": "No protocols attached to this call", - "no_dispatched": "No units dispatched to this call", - "no_timeline": "No timeline events available", - "contact_name": "Contact Name", - "contact_phone": "Phone", - "contact_email": "Email", - "unit": "Unit", - "status": "Status", - "reference_id": "Reference ID", - "external_id": "External ID", - "address": "Address", - "note": "Note", - "type": "Type", - "timestamp": "Timestamp", - "nature": "Nature", - "contact_info": "Contact Info", - "priority": "Priority", - "call_location": "Call Location", - "no_location_for_routing": "No location data available for routing", - "failed_to_open_maps": "Failed to open maps application", - "files": { - "button": "Files", - "title": "Call Files", - "open_error": "Error opening file", - "share_error": "Error sharing file", - "add_file": "Add File", - "file_name": "File Name", - "select_file": "Select File", - "upload": "Upload", - "uploading": "Uploading...", - "upload_error": "Error uploading file", - "no_files": "No files available", - "no_files_description": "Add files to your call to help with documentation and communication", - "empty": "No files available", - "empty_description": "Add files to your call to help with documentation and communication", - "error": "Error getting files", - "select_error": "Error selecting file", - "name_required": "Please enter a name for the file" - }, - "tabs": { - "info": "Info", - "contact": "Contact", - "protocols": "Protocols", - "dispatched": "Dispatched", - "timeline": "Activity" - } + "username": "Username", + "version": "Version", + "website": "Website" }, - "contacts": { - "title": "Contacts", - "description": "Add and manage your contacts", - "search": "Search contacts...", - "empty": "No contacts found", - "emptyDescription": "Add contacts to manage your personal and business connections", - "add": "Add Contact", - "edit": "Edit Contact", - "delete": "Delete", - "details": "Contact Details", - "person": "Person", - "company": "Company", - "contactType": "Contact Type", - "name": "Name", - "email": "Email", - "phone": "Phone", - "mobile": "Mobile", - "address": "Address", - "cityState": "City & State", - "city": "City", - "state": "State", - "zip": "Zip Code", + "tabs": { + "calls": "Calls", + "contacts": "Contacts", + "map": "Map", "notes": "Notes", - "important": "Mark as Important", - "save": "Save Contact", - "cancel": "Cancel", - "deleteConfirm": "Are you sure you want to delete this contact?", - "deleteSuccess": "Contact deleted successfully", - "saveSuccess": "Contact saved successfully", - "required": "Required", - "invalidEmail": "Invalid email address", - "formError": "Please fix the errors in the form" - }, - "loading": { - "loading": "Loading...", - "loadingData": "Loading data...", - "pleaseWait": "Please wait", - "processingRequest": "Processing your request..." - }, - "callNotes": { - "title": "Call Notes", - "searchPlaceholder": "Search notes...", - "addNotePlaceholder": "Add a new note...", - "addNote": "Add Note", - "noNotes": "No notes available for this call", - "noSearchResults": "No notes match your search" - }, - "callImages": { - "title": "Call Images", - "add": "Add Image", - "add_new": "Add New Image", - "select_from_gallery": "Select from Gallery", - "take_photo": "Take Photo", - "image_name": "Image Name", - "default_name": "Untitled Image", - "upload": "Upload", - "loading": "Loading...", - "no_images": "No images available", - "no_images_description": "Add images to your call to help with documentation and communication", - "error": "Error getting images" + "protocols": "Protocols", + "settings": "Settings" }, - "livekit": { - "title": "Voice Channels", - "no_rooms_available": "No voice channels available", - "join": "Join", - "connected_to_room": "Connected to Channel", - "speaking": "Speaking", - "mute": "Mute", - "unmute": "Unmute", - "disconnect": "Disconnect", - "connecting": "Connecting..." - } + "welcome": "Welcome to obytes app site" } diff --git a/src/translations/es.json b/src/translations/es.json index c3839571..357a9e98 100644 --- a/src/translations/es.json +++ b/src/translations/es.json @@ -2,95 +2,361 @@ "app": { "title": "Resgrid Unit" }, - "onboarding": { - "message": "Bienvenido a la aplicación Resgrid" + "callImages": { + "add": "Añadir imagen", + "add_new": "Añadir nueva imagen", + "default_name": "Imagen sin título", + "error": "Error al obtener imágenes", + "image_name": "Nombre de la imagen", + "loading": "Cargando...", + "no_images": "No hay imágenes disponibles", + "no_images_description": "Añade imágenes a tu llamada para ayudar con la documentación y comunicación", + "select_from_gallery": "Seleccionar de la galería", + "take_photo": "Tomar foto", + "title": "Imágenes de la llamada", + "upload": "Subir" }, - "tabs": { - "map": "Mapa", - "calls": "Llamadas", - "contacts": "Contactos", + "callNotes": { + "addNote": "Añadir nota", + "addNotePlaceholder": "Añadir una nueva nota...", + "noNotes": "No hay notas disponibles para esta llamada", + "noSearchResults": "No hay notas que coincidan con tu búsqueda", + "searchPlaceholder": "Buscar notas...", + "title": "Notas de la llamada" + }, + "call_detail": { + "address": "Dirección", + "call_location": "Ubicación de la llamada", + "contact_email": "Correo electrónico", + "contact_info": "Información de contacto", + "contact_name": "Nombre del contacto", + "contact_phone": "Teléfono", + "external_id": "ID externo", + "failed_to_open_maps": "Error al abrir la aplicación de mapas", + "files": { + "add_file": "Añadir archivo", + "button": "Archivos", + "empty": "No hay archivos disponibles", + "empty_description": "Añade archivos a tu llamada para ayudar con la documentación y comunicación", + "error": "Error al obtener archivos", + "file_name": "Nombre del archivo", + "name_required": "Por favor, introduce un nombre para el archivo", + "no_files": "No hay archivos disponibles", + "no_files_description": "Añade archivos a tu llamada para ayudar con la documentación y comunicación", + "open_error": "Error al abrir el archivo", + "select_error": "Error al seleccionar el archivo", + "select_file": "Seleccionar archivo", + "share_error": "Error al compartir el archivo", + "title": "Archivos de la llamada", + "upload": "Subir", + "upload_error": "Error al subir el archivo", + "uploading": "Subiendo..." + }, + "group": "Grupo", + "images": "Imágenes", + "loading": "Cargando detalles de la llamada...", + "nature": "Naturaleza", + "no_additional_info": "No hay información adicional disponible", + "no_contact_info": "No hay información de contacto disponible", + "no_dispatched": "No hay unidades despachadas a esta llamada", + "no_location": "No hay datos de ubicación disponibles", + "no_location_for_routing": "No hay datos de ubicación disponibles para el enrutamiento", + "no_protocols": "No hay protocolos adjuntos a esta llamada", + "no_timeline": "No hay eventos de línea de tiempo disponibles", + "not_available": "N/D", + "not_found": "Llamada no encontrada", + "note": "Nota", "notes": "Notas", - "protocols": "Protocolos", - "settings": "Configuración" + "priority": "Prioridad", + "reference_id": "ID de referencia", + "status": "Estado", + "tabs": { + "contact": "Contacto", + "dispatched": "Despachadas", + "info": "Información", + "protocols": "Protocolos", + "timeline": "Actividad" + }, + "timestamp": "Marca de tiempo", + "title": "Detalles de la llamada", + "type": "Tipo", + "unit": "Unidad" }, "calls": { - "title": "Llamadas", - "no_calls": "No hay llamadas activas", + "address": "Dirección", + "address_placeholder": "Introduce la dirección de la llamada", "call_details": "Detalles de la llamada", + "call_location": "Ubicación de la llamada", "call_number": "Número de llamada", "call_priority": "Prioridad de la llamada", + "confirm_deselect_message": "¿Estás seguro de que quieres deseleccionar la llamada activa actual?", + "confirm_deselect_title": "Deseleccionar llamada activa", + "contact_info": "Información de contacto", + "contact_info_placeholder": "Introduce la información del contacto", + "contact_name": "Nombre del contacto", + "contact_name_placeholder": "Introduce el nombre del contacto", + "contact_phone": "Teléfono del contacto", + "contact_phone_placeholder": "Introduce el teléfono del contacto", + "coordinates": "Coordenadas GPS", + "coordinates_placeholder": "Introduce coordenadas GPS (ej: 37.7749, -122.4194)", + "create": "Crear", + "create_error": "Error al crear la llamada", + "create_new_call": "Crear nueva llamada", + "create_success": "Llamada creada con éxito", + "description": "Descripción", + "description_placeholder": "Introduce la descripción de la llamada", + "deselect": "Deseleccionar", + "directions": "Direcciones", + "loading": "Cargando llamadas...", "loading_calls": "Cargando llamadas...", + "name": "Nombre", + "name_placeholder": "Introduce el nombre de la llamada", + "nature": "Naturaleza", + "nature_placeholder": "Introduce la naturaleza de la llamada", + "new_call": "Nueva llamada", + "new_call_description": "Crear una nueva llamada para iniciar un incidente", "no_call_selected": "Sin llamada activa", "no_call_selected_info": "Esta unidad no está respondiendo a ninguna llamada actualmente", + "no_calls": "No hay llamadas activas", + "no_calls_description": "No se encontraron llamadas activas. Seleccione una llamada activa para ver los detalles.", + "no_open_calls": "No hay llamadas abiertas disponibles", + "note": "Nota", + "note_placeholder": "Introduce la nota de la llamada", + "plus_code": "Código Plus", + "plus_code_placeholder": "Introduce código Plus (ej: 849VCWC8+R9)", + "priority": "Prioridad", + "priority_placeholder": "Selecciona la prioridad de la llamada", + "search": "Buscar llamadas...", "select_active_call": "Seleccionar llamada activa", + "select_address": "Seleccionar dirección", + "select_address_placeholder": "Selecciona la dirección de la llamada", + "select_description": "Seleccionar descripción", + "select_location": "Seleccionar ubicación en el mapa", + "select_name": "Seleccionar nombre", + "select_nature": "Seleccionar naturaleza", + "select_nature_placeholder": "Selecciona la naturaleza de la llamada", + "select_priority": "Seleccionar prioridad", + "select_priority_placeholder": "Selecciona la prioridad de la llamada", + "title": "Llamadas", + "viewNotes": "Notas", "view_details": "Ver detalles", - "directions": "Direcciones", - "deselect": "Deseleccionar", - "no_open_calls": "No hay llamadas abiertas disponibles", - "no_calls_description": "No se encontraron llamadas activas. Seleccione una llamada activa para ver los detalles.", - "confirm_deselect_title": "Deseleccionar llamada activa", - "confirm_deselect_message": "¿Estás seguro de que quieres deseleccionar la llamada activa actual?" + "what3words": "what3words", + "what3words_placeholder": "Introduce dirección what3words (ej: filled.count.soap)" }, "common": { + "add": "Añadir", "back": "Atrás", - "route": "Ruta", - "upload": "Subir", "cancel": "Cancelar", - "save": "Guardar", + "close": "Cerrar", + "confirm": "Confirmar", + "confirm_location": "Confirmar ubicación", "delete": "Eliminar", + "done": "Listo", "edit": "Editar", - "add": "Añadir", - "remove": "Eliminar", - "close": "Cerrar", - "unknown": "Desconocido", + "error": "Error", + "errorOccurred": "Ha ocurrido un error", + "get_my_location": "Obtener mi ubicación", + "go_back": "Volver", "loading": "Cargando...", "loading_address": "Cargando dirección...", - "done": "Listo", - "go_back": "Volver", - "search": "Buscar...", - "permission_denied": "Permiso denegado", - "uploading": "Subiendo...", - "error": "Error", - "share": "Compartir", "noDataAvailable": "No hay datos disponibles", - "tryAgainLater": "Por favor, inténtelo de nuevo más tarde", - "nothingToDisplay": "No hay nada que mostrar en este momento", - "errorOccurred": "Ha ocurrido un error", - "no_location": "No hay datos de ubicación disponibles", "no_address_found": "No se encontró dirección", - "get_my_location": "Obtener mi ubicación", - "confirm_location": "Confirmar ubicación", - "set_location": "Establecer ubicación", + "no_location": "No hay datos de ubicación disponibles", "no_unit_selected": "Ninguna unidad seleccionada", - "confirm": "Confirmar" + "nothingToDisplay": "No hay nada que mostrar en este momento", + "permission_denied": "Permiso denegado", + "remove": "Eliminar", + "route": "Ruta", + "save": "Guardar", + "search": "Buscar...", + "set_location": "Establecer ubicación", + "share": "Compartir", + "tryAgainLater": "Por favor, inténtelo de nuevo más tarde", + "unknown": "Desconocido", + "upload": "Subir", + "uploading": "Subiendo..." }, - "settings": { - "title": "Configuración", - "language": "Idioma", - "theme": { - "dark": "Oscuro", - "light": "Claro", - "system": "Sistema", - "title": "Tema" - } + "contacts": { + "add": "Añadir contacto", + "address": "Dirección", + "cancel": "Cancelar", + "city": "Ciudad", + "cityState": "Ciudad y Estado", + "company": "Empresa", + "contactType": "Tipo de contacto", + "delete": "Eliminar", + "deleteConfirm": "¿Estás seguro de que quieres eliminar este contacto?", + "deleteSuccess": "Contacto eliminado con éxito", + "description": "Añadir y gestionar tus contactos", + "details": "Detalles del contacto", + "edit": "Editar contacto", + "email": "Correo electrónico", + "empty": "No se encontraron contactos", + "emptyDescription": "Añade contactos para gestionar tus conexiones personales y comerciales", + "formError": "Por favor, corrige los errores en el formulario", + "important": "Marcar como importante", + "invalidEmail": "Dirección de correo electrónico no válida", + "mobile": "Móvil", + "name": "Nombre", + "notes": "Notas", + "person": "Persona", + "phone": "Teléfono", + "required": "Requerido", + "save": "Guardar contacto", + "saveSuccess": "Contacto guardado con éxito", + "search": "Buscar contactos...", + "state": "Estado", + "title": "Contactos", + "zip": "Código postal" + }, + "form": { + "invalid_url": "Por favor, introduce una URL válida que comience con http:// o https://", + "required": "Este campo es obligatorio" + }, + "livekit": { + "connected_to_room": "Conectado al canal", + "connecting": "Conectando...", + "disconnect": "Desconectar", + "join": "Unirse", + "mute": "Silenciar", + "no_rooms_available": "No hay canales de voz disponibles", + "speaking": "Hablando", + "title": "Canales de voz", + "unmute": "Activar sonido" + }, + "loading": { + "loading": "Cargando...", + "loadingData": "Cargando datos...", + "pleaseWait": "Por favor, espere", + "processingRequest": "Procesando su solicitud..." }, "login": { - "title": "Iniciar sesión", - "username": "Nombre de usuario", - "password": "Contraseña", + "errorModal": { + "confirmButton": "Aceptar", + "message": "Por favor, comprueba tu nombre de usuario y contraseña e inténtalo de nuevo.", + "title": "Inicio de sesión fallido" + }, "login": "Iniciar sesión", - "username_placeholder": "Introduce tu nombre de usuario", - "password_placeholder": "Introduce tu contraseña", "login_button": "Iniciar sesión", "login_button_description": "Inicia sesión en tu cuenta para continuar", - "login_button_loading": "Iniciando sesión...", "login_button_error": "Error al iniciar sesión", + "login_button_loading": "Iniciando sesión...", "login_button_success": "Sesión iniciada con éxito", + "password": "Contraseña", "password_incorrect": "La contraseña era incorrecta", - "errorModal": { - "title": "Inicio de sesión fallido", - "message": "Por favor, comprueba tu nombre de usuario y contraseña e inténtalo de nuevo.", - "confirmButton": "Aceptar" - } - } + "password_placeholder": "Introduce tu contraseña", + "title": "Iniciar sesión", + "username": "Nombre de usuario", + "username_placeholder": "Introduce tu nombre de usuario" + }, + "notes": { + "actions": { + "add": "Añadir nota", + "delete_confirm": "¿Estás seguro de que quieres eliminar esta nota?" + }, + "details": { + "close": "Cerrar", + "created": "Creado", + "delete": "Eliminar", + "edit": "Editar", + "tags": "Etiquetas", + "title": "Detalles de la nota", + "updated": "Actualizado" + }, + "empty": "No se encontraron notas", + "emptyDescription": "No se han creado notas para tu departamento todavía.", + "search": "Buscar notas...", + "title": "Notas" + }, + "onboarding": { + "message": "Bienvenido a la aplicación Resgrid" + }, + "protocols": { + "details": { + "close": "Cerrar", + "code": "Código", + "created": "Creado", + "title": "Detalles del protocolo", + "updated": "Actualizado" + }, + "empty": "No se encontraron protocolos", + "emptyDescription": "No se han creado protocolos para tu departamento todavía.", + "search": "Buscar protocolos...", + "title": "Protocolos" + }, + "roles": { + "modal": { + "title": "Asignaciones de roles de unidad" + }, + "selectUser": "Seleccionar usuario", + "status": "{{active}} de {{total}} roles activos", + "tap_to_manage": "Toca para gestionar roles", + "unassigned": "Sin asignar" + }, + "settings": { + "about": "Acerca de", + "account": "Cuenta", + "active_unit": "Unidad activa", + "app_info": "Información de la aplicación", + "app_name": "Nombre de la aplicación", + "arabic": "Árabe", + "background_location": "Ubicación en segundo plano", + "contact_us": "Contáctanos", + "english": "Inglés", + "enter_password": "Introduce tu contraseña", + "enter_server_url": "Introduce la URL de la API de Resgrid (ej: https://api.resgrid.com)", + "enter_username": "Introduce tu nombre de usuario", + "environment": "Entorno", + "general": "General", + "generale": "General", + "github": "Github", + "help_center": "Centro de ayuda", + "keep_screen_on": "Mantener pantalla encendida", + "language": "Idioma", + "links": "Enlaces", + "login_info": "Información de inicio de sesión", + "logout": "Cerrar sesión", + "more": "Más", + "no_units_available": "No hay unidades disponibles", + "none_selected": "Ninguna seleccionada", + "notifications": "Notificaciones push", + "notifications_description": "Activa las notificaciones para recibir alertas y actualizaciones", + "notifications_enable": "Activar notificaciones", + "password": "Contraseña", + "preferences": "Preferencias", + "privacy": "Política de privacidad", + "privacy_policy": "Política de privacidad", + "rate": "Calificar", + "select_unit": "Seleccionar unidad", + "server": "Servidor", + "server_url": "URL del servidor", + "server_url_note": "Nota: Esta es la URL de la API de Resgrid. Se utiliza para conectarse al servidor de Resgrid. No incluyas /api/v4 en la URL ni una barra diagonal al final.", + "set_active_unit": "Establecer unidad activa", + "share": "Compartir", + "spanish": "Español", + "status_page": "Estado del sistema", + "support": "Soporte", + "support_us": "Apóyanos", + "terms": "Términos de servicio", + "theme": { + "dark": "Oscuro", + "light": "Claro", + "system": "Sistema", + "title": "Tema" + }, + "title": "Configuración", + "unit_selection": "Selección de unidad", + "username": "Nombre de usuario", + "version": "Versión", + "website": "Sitio web" + }, + "tabs": { + "calls": "Llamadas", + "contacts": "Contactos", + "map": "Mapa", + "notes": "Notas", + "protocols": "Protocolos", + "settings": "Configuración" + }, + "welcome": "Bienvenido a la aplicación Resgrid" }