Compare commits

...

36 Commits

Author SHA1 Message Date
semantic-release-bot 7023875548 🔖 chore(release): v1.0.0-beta.34 [skip ci]
# [1.0.0-beta.34](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.33...v1.0.0-beta.34) (2025-04-02)

###  Features

* **admin**: Add application and rule management entries to localization files ([8b43e69](https://github.com/perfect-panel/ppanel-web/commit/8b43e69))
* **api**: Add an interface to obtain user subscription details, update related type definitions and localized text ([cf5c39c](https://github.com/perfect-panel/ppanel-web/commit/cf5c39c))
* **user**: Integrate subscription list into user management, update request parameters and types ([8d49dac](https://github.com/perfect-panel/ppanel-web/commit/8d49dac))

### 🐛 Bug Fixes

* **admin**: Hidden versions and system upgrades ([64cd842](https://github.com/perfect-panel/ppanel-web/commit/64cd842))
* **admin**: Modify the label type in the rule form to a string array ([a7aa5fe](https://github.com/perfect-panel/ppanel-web/commit/a7aa5fe))
* **node**: Handle potential null value for online users count ([fa2fb28](https://github.com/perfect-panel/ppanel-web/commit/fa2fb28))
* **subscribe**: Add value prop to field in subscription form for proper state management ([328838d](https://github.com/perfect-panel/ppanel-web/commit/328838d))
* **subscribe**: Refactor discount calculations and default selection logic in subscription forms ([423b240](https://github.com/perfect-panel/ppanel-web/commit/423b240))
* **subscribe**: Update default selection logic in subscription form to ensure proper state management ([ef15374](https://github.com/perfect-panel/ppanel-web/commit/ef15374))
2025-04-02 08:24:17 +00:00
web@ppanel a7aa5fee3e 🐛 fix(admin): Modify the label type in the rule form to a string array 2025-04-02 11:52:38 +07:00
web@ppanel 64cd842926 🐛 fix(admin): Hidden versions and system upgrades 2025-04-02 00:15:15 +07:00
web@ppanel 8b43e69bfe feat(admin): Add application and rule management entries to localization files 2025-04-02 00:12:02 +07:00
web@ppanel ef153747bd 🐛 fix(subscribe): Update default selection logic in subscription form to ensure proper state management 2025-04-01 12:37:17 +07:00
web@ppanel 328838d754 🐛 fix(subscribe): Add value prop to field in subscription form for proper state management 2025-03-30 20:27:03 +07:00
web@ppanel 423b24077f 🐛 fix(subscribe): Refactor discount calculations and default selection logic in subscription forms 2025-03-30 00:53:47 +07:00
web@ppanel fa2fb2864f 🐛 fix(node): Handle potential null value for online users count 2025-03-29 23:43:21 +07:00
web@ppanel 8d49daca21 feat(user): Integrate subscription list into user management, update request parameters and types 2025-03-26 15:01:43 +07:00
web@ppanel cf5c39cfe5 feat(api): Add an interface to obtain user subscription details, update related type definitions and localized text 2025-03-25 23:55:31 +07:00
semantic-release-bot 383638f702 🔖 chore(release): v1.0.0-beta.33 [skip ci]
# [1.0.0-beta.33](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.32...v1.0.0-beta.33) (2025-03-18)

### 🐛 Bug Fixes

* **subscribe**: Handle optional values in price and discount calculations ([5939763](https://github.com/perfect-panel/ppanel-web/commit/5939763))
2025-03-18 07:53:53 +00:00
web@ppanel 5939763b57 🐛 fix(subscribe): Handle optional values in price and discount calculations 2025-03-18 14:50:48 +07:00
semantic-release-bot fa56eb8293 🔖 chore(release): v1.0.0-beta.32 [skip ci]
# [1.0.0-beta.32](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.31...v1.0.0-beta.32) (2025-03-17)

### 🐛 Bug Fixes

* **forms**: Add step attribute to number inputs for better value control ([b8f4f1e](https://github.com/perfect-panel/ppanel-web/commit/b8f4f1e))
* **locales**: Update invite code text to indicate it's optional ([6a34bfb](https://github.com/perfect-panel/ppanel-web/commit/6a34bfb))
2025-03-17 15:53:15 +00:00
web@ppanel 6a34bfb78d 🐛 fix(locales): Update invite code text to indicate it's optional 2025-03-17 22:50:21 +07:00
web@ppanel b8f4f1e694 🐛 fix(forms): Add step attribute to number inputs for better value control 2025-03-17 22:47:42 +07:00
semantic-release-bot aa1d42651d 🔖 chore(release): v1.0.0-beta.31 [skip ci]
# [1.0.0-beta.31](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.30...v1.0.0-beta.31) (2025-03-15)

### 🐛 Bug Fixes

* **site**: Se ref to store site configuration for updates ([0c8f091](https://github.com/perfect-panel/ppanel-web/commit/0c8f091))
2025-03-15 15:51:45 +00:00
web@ppanel 0c8f0911c7 🐛 fix(site): Se ref to store site configuration for updates 2025-03-15 22:47:19 +07:00
semantic-release-bot db0d9e003e 🔖 chore(release): v1.0.0-beta.30 [skip ci]
# [1.0.0-beta.30](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.29...v1.0.0-beta.30) (2025-03-15)

###  Features

* **api**: Add CheckoutOrder request and response types, and update user purchase request parameters ([48a1b97](https://github.com/perfect-panel/ppanel-web/commit/48a1b97))
* **email**: Add traffic exhaustion template ([bb3bd7b](https://github.com/perfect-panel/ppanel-web/commit/bb3bd7b))
* **formatting**: Update differenceInDays function to return whole days or two decimal places ([bf58f25](https://github.com/perfect-panel/ppanel-web/commit/bf58f25))
* **global**: Add custom data ([6dbebd1](https://github.com/perfect-panel/ppanel-web/commit/6dbebd1))
* **input**: Add minimum value constraint and enhance number handling in EnhancedInput ([ce31972](https://github.com/perfect-panel/ppanel-web/commit/ce31972))
* **loading**: Replace loading animation with a simpler spinner and loading text ([f72df3a](https://github.com/perfect-panel/ppanel-web/commit/f72df3a))
* **node-form**: Update number input fields to enforce step, min, and max values ([3f7b6d1](https://github.com/perfect-panel/ppanel-web/commit/3f7b6d1))
* **payment**: Add isEdit prop to PaymentForm and disable fields when editing ([85f55de](https://github.com/perfect-panel/ppanel-web/commit/85f55de))
* **timeline**: Simplify timeline component layout and remove commented-out code ([fbad3b0](https://github.com/perfect-panel/ppanel-web/commit/fbad3b0))

### 🎫 Chores

* **release**: V1.0.0-beta.27 [skip ci] ([092477b](https://github.com/perfect-panel/ppanel-web/commit/092477b))
* **release**: V1.0.0-beta.28 [skip ci] ([786ba0e](https://github.com/perfect-panel/ppanel-web/commit/786ba0e))
* Merge branch 'beta' into develop ([f219c52](https://github.com/perfect-panel/ppanel-web/commit/f219c52))

### 🐛 Bug Fixes

* **dashboard**:  Update date display to use start_time if available ([e551232](https://github.com/perfect-panel/ppanel-web/commit/e551232))
2025-03-15 09:02:24 +00:00
web@ppanel f219c52306 🔧 chore: Merge branch 'beta' into develop 2025-03-15 15:58:37 +07:00
web@ppanel 3f7b6d16ed feat(node-form): Update number input fields to enforce step, min, and max values 2025-03-15 15:48:59 +07:00
web@ppanel 6dbebd152d feat(global): Add custom data 2025-03-15 15:39:55 +07:00
web@ppanel bb3bd7b50c feat(email): Add traffic exhaustion template 2025-03-14 23:28:36 +07:00
web@ppanel fbad3b0e51 feat(timeline): Simplify timeline component layout and remove commented-out code 2025-03-14 23:21:17 +07:00
web@ppanel e551232564 🐛 fix(dashboard): Update date display to use start_time if available 2025-03-14 22:10:24 +07:00
web@ppanel bf58f25072 feat(formatting): Update differenceInDays function to return whole days or two decimal places 2025-03-14 20:51:17 +07:00
web@ppanel 85f55def2e feat(payment): Add isEdit prop to PaymentForm and disable fields when editing 2025-03-14 14:04:10 +07:00
semantic-release-bot 29bc3c7722 🔖 chore(release): v1.0.0-beta.29 [skip ci]
# [1.0.0-beta.29](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.28...v1.0.0-beta.29) (2025-03-14)

###  Features

* **api**: Add CheckoutOrder request and response types, and update user purchase request parameters ([dddc21c](https://github.com/perfect-panel/ppanel-web/commit/dddc21c))
* **loading**: Replace loading animation with a simpler spinner and loading text ([b8316bb](https://github.com/perfect-panel/ppanel-web/commit/b8316bb))
2025-03-14 06:43:47 +00:00
web@ppanel f72df3a5e8 feat(loading): Replace loading animation with a simpler spinner and loading text 2025-03-14 13:42:58 +07:00
web@ppanel 48a1b97051 feat(api): Add CheckoutOrder request and response types, and update user purchase request parameters 2025-03-14 13:42:58 +07:00
semantic-release-bot 786ba0e41c 🔖 chore(release): v1.0.0-beta.28 [skip ci]
# [1.0.0-beta.28](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.27...v1.0.0-beta.28) (2025-03-13)

###  Features

* **input**: Add minimum value constraint and enhance number handling in EnhancedInput ([94822d9](https://github.com/perfect-panel/ppanel-web/commit/94822d9))
2025-03-14 13:42:58 +07:00
web@ppanel ce3197298d feat(input): Add minimum value constraint and enhance number handling in EnhancedInput 2025-03-14 13:42:58 +07:00
semantic-release-bot 092477b2d3 🔖 chore(release): v1.0.0-beta.27 [skip ci]
* **payment**: Reconstruct the payment page ([7109472](https://github.com/perfect-panel/ppanel-web/commit/7109472))
* Enhance user navigation dropdown ui and styling ([d2732e6](https://github.com/perfect-panel/ppanel-web/commit/d2732e6))

* **cdn**: Add CDN URL configuration and update related references ([0c90733](https://github.com/perfect-panel/ppanel-web/commit/0c90733))
* **payment**: Add bank card payment ([7fa3a57](https://github.com/perfect-panel/ppanel-web/commit/7fa3a57))
* **subscription**:  Improve layout and organization of subscription detail tabs ([e4630f8](https://github.com/perfect-panel/ppanel-web/commit/e4630f8))
* **subscription**: Refactor subscription handling and update imports for better organization ([2215c7f](https://github.com/perfect-panel/ppanel-web/commit/2215c7f))

* **merge**: Bump version to 1.0.0-beta.26 and update changelog ([3222016](https://github.com/perfect-panel/ppanel-web/commit/3222016))

* **affiliate**: Update user identifier ([35f92c9](https://github.com/perfect-panel/ppanel-web/commit/35f92c9))
* **changelog**: Update change log style ([cfa3fc0](https://github.com/perfect-panel/ppanel-web/commit/cfa3fc0))
* **payment**: Add notification URL field to payment management interface ([5c710e1](https://github.com/perfect-panel/ppanel-web/commit/5c710e1))
* **payment**: Fix payment related type definitions and update payment method references ([c3138a8](https://github.com/perfect-panel/ppanel-web/commit/c3138a8))
* **payment**: Refactor purchaseCheckout usage and remove redundant code ([a5e2079](https://github.com/perfect-panel/ppanel-web/commit/a5e2079))
* **payment**: Update checkout type from 'link' to 'url' for consistency ([136a1ab](https://github.com/perfect-panel/ppanel-web/commit/136a1ab))
* **payment**: Update payment information ([70d6a38](https://github.com/perfect-panel/ppanel-web/commit/70d6a38))
* **payment**: Update payment method update logic to include row data ([6752420](https://github.com/perfect-panel/ppanel-web/commit/6752420))
* **purchasing**: Update payment type to lowercase and add optional chaining for discounts ([c06ea49](https://github.com/perfect-panel/ppanel-web/commit/c06ea49))
* **ui**: Improve dashboard layout and enhance button functionality; open checkout URLs in a new tab ([fc0da76](https://github.com/perfect-panel/ppanel-web/commit/fc0da76))
* **ui**: Multiple display bugs ([f5d8fd3](https://github.com/perfect-panel/ppanel-web/commit/f5d8fd3))
2025-03-14 13:42:58 +07:00
web@ppanel b8316bba33 feat(loading): Replace loading animation with a simpler spinner and loading text 2025-03-14 13:40:56 +07:00
web@ppanel dddc21c686 feat(api): Add CheckoutOrder request and response types, and update user purchase request parameters 2025-03-14 13:34:36 +07:00
semantic-release-bot d10ecc9fdf 🔖 chore(release): v1.0.0-beta.28 [skip ci]
# [1.0.0-beta.28](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.27...v1.0.0-beta.28) (2025-03-13)

###  Features

* **input**: Add minimum value constraint and enhance number handling in EnhancedInput ([94822d9](https://github.com/perfect-panel/ppanel-web/commit/94822d9))
2025-03-13 10:35:19 +00:00
web@ppanel 94822d902f feat(input): Add minimum value constraint and enhance number handling in EnhancedInput 2025-03-13 17:32:36 +07:00
190 changed files with 13064 additions and 363 deletions
+156 -27
View File
@@ -1,41 +1,170 @@
<a name="readme-top"></a> <a name="readme-top"></a>
# Changelog # Changelog
# [1.0.0-beta.27](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.26...v1.0.0-beta.27) (2025-03-13) # [1.0.0-beta.34](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.33...v1.0.0-beta.34) (2025-04-02)
### ♻ Code Refactoring
* **payment**: Reconstruct the payment page ([7109472](https://github.com/perfect-panel/ppanel-web/commit/7109472))
* Enhance user navigation dropdown ui and styling ([d2732e6](https://github.com/perfect-panel/ppanel-web/commit/d2732e6))
### ✨ Features ### ✨ Features
* **cdn**: Add CDN URL configuration and update related references ([0c90733](https://github.com/perfect-panel/ppanel-web/commit/0c90733)) * **admin**: Add application and rule management entries to localization files ([8b43e69](https://github.com/perfect-panel/ppanel-web/commit/8b43e69))
* **payment**: Add bank card payment ([7fa3a57](https://github.com/perfect-panel/ppanel-web/commit/7fa3a57)) * **api**: Add an interface to obtain user subscription details, update related type definitions and localized text ([cf5c39c](https://github.com/perfect-panel/ppanel-web/commit/cf5c39c))
* **subscription**: Improve layout and organization of subscription detail tabs ([e4630f8](https://github.com/perfect-panel/ppanel-web/commit/e4630f8)) * **user**: Integrate subscription list into user management, update request parameters and types ([8d49dac](https://github.com/perfect-panel/ppanel-web/commit/8d49dac))
* **subscription**: Refactor subscription handling and update imports for better organization ([2215c7f](https://github.com/perfect-panel/ppanel-web/commit/2215c7f))
### 🎫 Chores
* **merge**: Bump version to 1.0.0-beta.26 and update changelog ([3222016](https://github.com/perfect-panel/ppanel-web/commit/3222016))
### 🐛 Bug Fixes ### 🐛 Bug Fixes
* **affiliate**: Update user identifier ([35f92c9](https://github.com/perfect-panel/ppanel-web/commit/35f92c9)) * **admin**: Hidden versions and system upgrades ([64cd842](https://github.com/perfect-panel/ppanel-web/commit/64cd842))
* **changelog**: Update change log style ([cfa3fc0](https://github.com/perfect-panel/ppanel-web/commit/cfa3fc0)) * **admin**: Modify the label type in the rule form to a string array ([a7aa5fe](https://github.com/perfect-panel/ppanel-web/commit/a7aa5fe))
* **payment**: Add notification URL field to payment management interface ([5c710e1](https://github.com/perfect-panel/ppanel-web/commit/5c710e1)) * **node**: Handle potential null value for online users count ([fa2fb28](https://github.com/perfect-panel/ppanel-web/commit/fa2fb28))
* **payment**: Fix payment related type definitions and update payment method references ([c3138a8](https://github.com/perfect-panel/ppanel-web/commit/c3138a8)) * **subscribe**: Add value prop to field in subscription form for proper state management ([328838d](https://github.com/perfect-panel/ppanel-web/commit/328838d))
* **payment**: Refactor purchaseCheckout usage and remove redundant code ([a5e2079](https://github.com/perfect-panel/ppanel-web/commit/a5e2079)) * **subscribe**: Refactor discount calculations and default selection logic in subscription forms ([423b240](https://github.com/perfect-panel/ppanel-web/commit/423b240))
* **payment**: Update checkout type from 'link' to 'url' for consistency ([136a1ab](https://github.com/perfect-panel/ppanel-web/commit/136a1ab)) * **subscribe**: Update default selection logic in subscription form to ensure proper state management ([ef15374](https://github.com/perfect-panel/ppanel-web/commit/ef15374))
* **payment**: Update payment information ([70d6a38](https://github.com/perfect-panel/ppanel-web/commit/70d6a38))
* **payment**: Update payment method update logic to include row data ([6752420](https://github.com/perfect-panel/ppanel-web/commit/6752420)) <a name="readme-top"></a>
* **purchasing**: Update payment type to lowercase and add optional chaining for discounts ([c06ea49](https://github.com/perfect-panel/ppanel-web/commit/c06ea49))
* **ui**: Improve dashboard layout and enhance button functionality; open checkout URLs in a new tab ([fc0da76](https://github.com/perfect-panel/ppanel-web/commit/fc0da76)) # Changelog
* **ui**: Multiple display bugs ([f5d8fd3](https://github.com/perfect-panel/ppanel-web/commit/f5d8fd3))
# [1.0.0-beta.33](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.32...v1.0.0-beta.33) (2025-03-18)
### 🐛 Bug Fixes
- **subscribe**: Handle optional values in price and discount calculations ([5939763](https://github.com/perfect-panel/ppanel-web/commit/5939763))
# [1.0.0-beta.32](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.31...v1.0.0-beta.32) (2025-03-17)
### 🐛 Bug Fixes
- **forms**: Add step attribute to number inputs for better value control ([b8f4f1e](https://github.com/perfect-panel/ppanel-web/commit/b8f4f1e))
- **locales**: Update invite code text to indicate it's optional ([6a34bfb](https://github.com/perfect-panel/ppanel-web/commit/6a34bfb))
<a name="readme-top"></a>
# Changelog
# [1.0.0-beta.31](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.30...v1.0.0-beta.31) (2025-03-15)
### 🐛 Bug Fixes
- **site**: Se ref to store site configuration for updates ([0c8f091](https://github.com/perfect-panel/ppanel-web/commit/0c8f091))
# [1.0.0-beta.30](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.29...v1.0.0-beta.30) (2025-03-15)
### ✨ Features
- **api**: Add CheckoutOrder request and response types, and update user purchase request parameters ([48a1b97](https://github.com/perfect-panel/ppanel-web/commit/48a1b97))
- **email**: Add traffic exhaustion template ([bb3bd7b](https://github.com/perfect-panel/ppanel-web/commit/bb3bd7b))
- **formatting**: Update differenceInDays function to return whole days or two decimal places ([bf58f25](https://github.com/perfect-panel/ppanel-web/commit/bf58f25))
- **global**: Add custom data ([6dbebd1](https://github.com/perfect-panel/ppanel-web/commit/6dbebd1))
- **input**: Add minimum value constraint and enhance number handling in EnhancedInput ([ce31972](https://github.com/perfect-panel/ppanel-web/commit/ce31972))
- **loading**: Replace loading animation with a simpler spinner and loading text ([f72df3a](https://github.com/perfect-panel/ppanel-web/commit/f72df3a))
- **node-form**: Update number input fields to enforce step, min, and max values ([3f7b6d1](https://github.com/perfect-panel/ppanel-web/commit/3f7b6d1))
- **payment**: Add isEdit prop to PaymentForm and disable fields when editing ([85f55de](https://github.com/perfect-panel/ppanel-web/commit/85f55de))
- **timeline**: Simplify timeline component layout and remove commented-out code ([fbad3b0](https://github.com/perfect-panel/ppanel-web/commit/fbad3b0))
### 🎫 Chores
- **release**: V1.0.0-beta.27 [skip ci] ([092477b](https://github.com/perfect-panel/ppanel-web/commit/092477b))
- **release**: V1.0.0-beta.28 [skip ci] ([786ba0e](https://github.com/perfect-panel/ppanel-web/commit/786ba0e))
- Merge branch 'beta' into develop ([f219c52](https://github.com/perfect-panel/ppanel-web/commit/f219c52))
### 🐛 Bug Fixes
- **dashboard**: Update date display to use start_time if available ([e551232](https://github.com/perfect-panel/ppanel-web/commit/e551232))
<a name="readme-top"></a>
# Changelog
# [1.0.0-beta.29](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.28...v1.0.0-beta.29) (2025-03-14)
### ✨ Features
- **api**: Add CheckoutOrder request and response types, and update user purchase request parameters ([dddc21c](https://github.com/perfect-panel/ppanel-web/commit/dddc21c))
- **loading**: Replace loading animation with a simpler spinner and loading text ([b8316bb](https://github.com/perfect-panel/ppanel-web/commit/b8316bb))
<a name="readme-top"></a>
# Changelog
# [1.0.0-beta.28](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.27...v1.0.0-beta.28) (2025-03-13)
### ✨ Features
- **input**: Add minimum value constraint and enhance number handling in EnhancedInput ([94822d9](https://github.com/perfect-panel/ppanel-web/commit/94822d9))
# [1.0.0-beta.27](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.26...v1.0.0-beta.27) (2025-03-13)
### ♻ Code Refactoring
- **payment**: Reconstruct the payment page ([7109472](https://github.com/perfect-panel/ppanel-web/commit/7109472))
- Enhance user navigation dropdown ui and styling ([d2732e6](https://github.com/perfect-panel/ppanel-web/commit/d2732e6))
### ✨ Features
- **cdn**: Add CDN URL configuration and update related references ([0c90733](https://github.com/perfect-panel/ppanel-web/commit/0c90733))
- **payment**: Add bank card payment ([7fa3a57](https://github.com/perfect-panel/ppanel-web/commit/7fa3a57))
- **subscription**: Improve layout and organization of subscription detail tabs ([e4630f8](https://github.com/perfect-panel/ppanel-web/commit/e4630f8))
- **subscription**: Refactor subscription handling and update imports for better organization ([2215c7f](https://github.com/perfect-panel/ppanel-web/commit/2215c7f))
### 🎫 Chores
- **merge**: Bump version to 1.0.0-beta.26 and update changelog ([3222016](https://github.com/perfect-panel/ppanel-web/commit/3222016))
### 🐛 Bug Fixes
- **affiliate**: Update user identifier ([35f92c9](https://github.com/perfect-panel/ppanel-web/commit/35f92c9))
- **changelog**: Update change log style ([cfa3fc0](https://github.com/perfect-panel/ppanel-web/commit/cfa3fc0))
- **payment**: Add notification URL field to payment management interface ([5c710e1](https://github.com/perfect-panel/ppanel-web/commit/5c710e1))
- **payment**: Fix payment related type definitions and update payment method references ([c3138a8](https://github.com/perfect-panel/ppanel-web/commit/c3138a8))
- **payment**: Refactor purchaseCheckout usage and remove redundant code ([a5e2079](https://github.com/perfect-panel/ppanel-web/commit/a5e2079))
- **payment**: Update checkout type from 'link' to 'url' for consistency ([136a1ab](https://github.com/perfect-panel/ppanel-web/commit/136a1ab))
- **payment**: Update payment information ([70d6a38](https://github.com/perfect-panel/ppanel-web/commit/70d6a38))
- **payment**: Update payment method update logic to include row data ([6752420](https://github.com/perfect-panel/ppanel-web/commit/6752420))
- **purchasing**: Update payment type to lowercase and add optional chaining for discounts ([c06ea49](https://github.com/perfect-panel/ppanel-web/commit/c06ea49))
- **ui**: Improve dashboard layout and enhance button functionality; open checkout URLs in a new tab ([fc0da76](https://github.com/perfect-panel/ppanel-web/commit/fc0da76))
- **ui**: Multiple display bugs ([f5d8fd3](https://github.com/perfect-panel/ppanel-web/commit/f5d8fd3))
<a name="readme-top"></a>
# Changelog
# [1.0.0-beta.28](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.27...v1.0.0-beta.28) (2025-03-13)
### ✨ Features
- **input**: Add minimum value constraint and enhance number handling in EnhancedInput ([94822d9](https://github.com/perfect-panel/ppanel-web/commit/94822d9))
# [1.0.0-beta.27](https://github.com/perfect-panel/ppanel-web/compare/v1.0.0-beta.26...v1.0.0-beta.27) (2025-03-13)
### ♻ Code Refactoring
- **payment**: Reconstruct the payment page ([7109472](https://github.com/perfect-panel/ppanel-web/commit/7109472))
- Enhance user navigation dropdown ui and styling ([d2732e6](https://github.com/perfect-panel/ppanel-web/commit/d2732e6))
### ✨ Features
- **cdn**: Add CDN URL configuration and update related references ([0c90733](https://github.com/perfect-panel/ppanel-web/commit/0c90733))
- **payment**: Add bank card payment ([7fa3a57](https://github.com/perfect-panel/ppanel-web/commit/7fa3a57))
- **subscription**: Improve layout and organization of subscription detail tabs ([e4630f8](https://github.com/perfect-panel/ppanel-web/commit/e4630f8))
- **subscription**: Refactor subscription handling and update imports for better organization ([2215c7f](https://github.com/perfect-panel/ppanel-web/commit/2215c7f))
### 🎫 Chores
- **merge**: Bump version to 1.0.0-beta.26 and update changelog ([3222016](https://github.com/perfect-panel/ppanel-web/commit/3222016))
### 🐛 Bug Fixes
- **affiliate**: Update user identifier ([35f92c9](https://github.com/perfect-panel/ppanel-web/commit/35f92c9))
- **changelog**: Update change log style ([cfa3fc0](https://github.com/perfect-panel/ppanel-web/commit/cfa3fc0))
- **payment**: Add notification URL field to payment management interface ([5c710e1](https://github.com/perfect-panel/ppanel-web/commit/5c710e1))
- **payment**: Fix payment related type definitions and update payment method references ([c3138a8](https://github.com/perfect-panel/ppanel-web/commit/c3138a8))
- **payment**: Refactor purchaseCheckout usage and remove redundant code ([a5e2079](https://github.com/perfect-panel/ppanel-web/commit/a5e2079))
- **payment**: Update checkout type from 'link' to 'url' for consistency ([136a1ab](https://github.com/perfect-panel/ppanel-web/commit/136a1ab))
- **payment**: Update payment information ([70d6a38](https://github.com/perfect-panel/ppanel-web/commit/70d6a38))
- **payment**: Update payment method update logic to include row data ([6752420](https://github.com/perfect-panel/ppanel-web/commit/6752420))
- **purchasing**: Update payment type to lowercase and add optional chaining for discounts ([c06ea49](https://github.com/perfect-panel/ppanel-web/commit/c06ea49))
- **ui**: Improve dashboard layout and enhance button functionality; open checkout URLs in a new tab ([fc0da76](https://github.com/perfect-panel/ppanel-web/commit/fc0da76))
- **ui**: Multiple display bugs ([f5d8fd3](https://github.com/perfect-panel/ppanel-web/commit/f5d8fd3))
<a name="readme-top"></a> <a name="readme-top"></a>
@@ -232,16 +232,6 @@ export default function SubscribeAppForm<
name: 'is_default', name: 'is_default',
type: 'boolean', type: 'boolean',
placeholder: t('defaultVersion'), placeholder: t('defaultVersion'),
calculateValue: (value) => {
const newField = field.value?.map((item) => {
if (item.is_default) {
item.is_default = false;
}
return item;
});
form.setValue(field.name, newField);
return value;
},
}, },
{ {
name: 'url', name: 'url',
@@ -252,10 +242,32 @@ export default function SubscribeAppForm<
]} ]}
value={field.value} value={field.value}
onChange={(value) => { onChange={(value) => {
form.setValue( const filteredValue = value.filter((item) => item.url);
field.name,
value.filter((item) => item.url), const newDefaultIndex = value.findIndex(
(item, idx) =>
item.is_default &&
(!field.value?.[idx] || !field.value[idx].is_default),
); );
let finalValue = filteredValue;
if (newDefaultIndex >= 0 && filteredValue[newDefaultIndex]) {
finalValue = filteredValue.map((item, index) => ({
...item,
is_default: index === newDefaultIndex,
}));
} else if (
!filteredValue.some((item) => item.is_default) &&
filteredValue.length > 0
) {
finalValue = filteredValue.map((item, index) => ({
...item,
is_default: index === 0,
}));
}
form.setValue(field.name, finalValue as any);
}} }}
/> />
</FormControl> </FormControl>
@@ -286,31 +286,34 @@ export default function Page() {
</TabsContent> </TabsContent>
<TabsContent value='template'> <TabsContent value='template'>
<div className='grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3'> <div className='grid grid-cols-1 gap-4 md:grid-cols-2'>
{['verify_email_template', 'expiration_email_template', 'maintenance_email_template'].map( {[
(templateKey) => ( 'verify_email_template',
<Card key={templateKey}> 'expiration_email_template',
<CardHeader> 'maintenance_email_template',
<CardTitle>{t(`${templateKey}`)}</CardTitle> 'traffic_exceed_email_template',
<CardDescription> ].map((templateKey) => (
{t(`${templateKey}Description`, { after: '{{', before: '}}' })} <Card key={templateKey}>
</CardDescription> <CardHeader>
</CardHeader> <CardTitle>{t(`${templateKey}`)}</CardTitle>
<CardContent> <CardDescription>
<HTMLEditor {t(`${templateKey}Description`, { after: '{{', before: '}}' })}
placeholder={t('inputPlaceholder')} </CardDescription>
value={data?.config?.[templateKey] as string} </CardHeader>
onBlur={(value) => <CardContent>
updateConfig('config', { <HTMLEditor
...data?.config, placeholder={t('inputPlaceholder')}
[templateKey]: value, value={data?.config?.[templateKey] as string}
}) onBlur={(value) =>
} updateConfig('config', {
/> ...data?.config,
</CardContent> [templateKey]: value,
</Card> })
), }
)} />
</CardContent>
</Card>
))}
</div> </div>
</TabsContent> </TabsContent>
@@ -307,6 +307,7 @@ export default function CouponForm<T extends Record<string, any>>({
<EnhancedInput <EnhancedInput
placeholder={t('form.countPlaceholder')} placeholder={t('form.countPlaceholder')}
type='number' type='number'
step={1}
{...field} {...field}
onValueChange={(value) => { onValueChange={(value) => {
form.setValue(field.name, value); form.setValue(field.name, value);
@@ -327,6 +328,7 @@ export default function CouponForm<T extends Record<string, any>>({
<EnhancedInput <EnhancedInput
placeholder={t('form.userLimitPlaceholder')} placeholder={t('form.userLimitPlaceholder')}
type='number' type='number'
step={1}
{...field} {...field}
onValueChange={(value) => { onValueChange={(value) => {
form.setValue(field.name, value); form.setValue(field.name, value);
@@ -45,6 +45,7 @@ interface PaymentFormProps<T> {
loading?: boolean; loading?: boolean;
initialValues?: T; initialValues?: T;
onSubmit: (values: T) => Promise<boolean>; onSubmit: (values: T) => Promise<boolean>;
isEdit?: boolean;
} }
export default function PaymentForm<T>({ export default function PaymentForm<T>({
@@ -53,6 +54,7 @@ export default function PaymentForm<T>({
loading, loading,
initialValues, initialValues,
onSubmit, onSubmit,
isEdit,
}: PaymentFormProps<T>) { }: PaymentFormProps<T>) {
const t = useTranslations('payment'); const t = useTranslations('payment');
const { common } = useGlobalStore(); const { common } = useGlobalStore();
@@ -317,6 +319,8 @@ export default function PaymentForm<T>({
}} }}
defaultValue={field.value} defaultValue={field.value}
value={field.value} value={field.value}
// @ts-expect-error
disabled={isEdit && Boolean(initialValues?.platform)}
> >
<FormControl> <FormControl>
<SelectTrigger> <SelectTrigger>
@@ -136,6 +136,7 @@ export default function PaymentTable() {
actions={{ actions={{
render: (row) => [ render: (row) => [
<PaymentForm<API.UpdatePaymentMethodRequest> <PaymentForm<API.UpdatePaymentMethodRequest>
isEdit
key='edit' key='edit'
trigger={<Button>{t('edit')}</Button>} trigger={<Button>{t('edit')}</Button>}
title={t('editPayment')} title={t('editPayment')}
@@ -0,0 +1,215 @@
'use client';
import { createRuleGroup } from '@/services/admin/server';
import { Button } from '@workspace/ui/components/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@workspace/ui/components/dialog';
import { Label } from '@workspace/ui/components/label';
import { Progress } from '@workspace/ui/components/progress';
import { Textarea } from '@workspace/ui/components/textarea';
import { Icon } from '@workspace/ui/custom-components/icon';
import yaml from 'js-yaml';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
interface ImportYamlRulesProps {
onImportSuccess?: () => void;
}
interface RuleGroup {
name: string;
rules: string[];
}
export default function ImportYamlRules({ onImportSuccess }: ImportYamlRulesProps) {
const t = useTranslations('rules');
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [yamlContent, setYamlContent] = useState('');
const [importProgress, setImportProgress] = useState(0);
const [importTotal, setImportTotal] = useState(0);
const [analyzing, setAnalyzing] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (event) => {
const content = event.target?.result as string;
setYamlContent(content);
setOpen(true);
};
reader.readAsText(file);
e.target.value = '';
};
const processRule = (rule: string): { policyGroup: string; cleanRule: string } | null => {
const parts = rule.split(',');
if (parts.length === 1) {
return null;
}
let policyGroup = 'default';
let cleanRule = rule;
if (parts.length >= 3) {
const thirdPart = parts[2]?.trim();
if (thirdPart) {
policyGroup = thirdPart;
}
}
cleanRule = parts.slice(0, 2).join(',');
return { policyGroup, cleanRule };
};
const parseRulesIntoGroups = (rules: string[]): Record<string, string[]> => {
const groups: Record<string, string[]> = {};
for (const rule of rules) {
if (!rule.trim()) continue;
const result = processRule(rule);
if (result === null) continue;
const { policyGroup, cleanRule } = result;
if (!groups[policyGroup]) {
groups[policyGroup] = [];
}
groups[policyGroup].push(cleanRule);
}
return groups;
};
const handleImport = async () => {
if (!yamlContent) {
toast.error(t('pleaseUploadFile'));
return;
}
setLoading(true);
setAnalyzing(true);
try {
const parsedYaml = yaml.load(yamlContent) as any;
if (!parsedYaml || !parsedYaml.rules) {
throw new Error(t('invalidYamlFormat'));
}
let allRules: string[] = [];
if (Array.isArray(parsedYaml.rules)) {
allRules = parsedYaml.rules.filter((rule: string) => rule.trim());
}
if (allRules.length === 0) {
throw new Error(t('noValidRules'));
}
const ruleGroups = parseRulesIntoGroups(allRules);
const groups = Object.entries(ruleGroups).map(([name, rules]) => ({
name,
rules,
}));
setImportTotal(groups.length);
setAnalyzing(false);
for (let i = 0; i < groups.length; i++) {
const group = groups[i];
if (!group?.name || !group?.rules.length) continue;
await createRuleGroup({
name: group.name,
rules: group?.rules.join('\n'),
enable: false,
tags: [],
icon: '',
});
setImportProgress(i + 1);
}
toast.success(t('importSuccess'));
setOpen(false);
setYamlContent('');
setImportProgress(0);
setImportTotal(0);
onImportSuccess?.();
} catch (error) {
console.error('Import error:', error);
toast.error(error instanceof Error ? error.message : t('importFailed'));
} finally {
setLoading(false);
setAnalyzing(false);
}
};
return (
<>
<input
ref={fileInputRef}
type='file'
accept='.yml,.yaml'
style={{ display: 'none' }}
onChange={handleFileUpload}
/>
<Button variant='default' onClick={() => fileInputRef.current?.click()}>
{t('import')}
</Button>
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className='sm:max-w-[500px]'>
<DialogHeader>
<DialogTitle>{t('importYamlRules')}</DialogTitle>
<DialogDescription>{t('importYamlDescription')}</DialogDescription>
</DialogHeader>
<div className='grid gap-4 py-4'>
{yamlContent && (
<div className='grid gap-2'>
<Label htmlFor='preview'>{t('preview')}</Label>
<Textarea
id='preview'
value={yamlContent}
readOnly
rows={10}
className='font-mono text-xs'
/>
</div>
)}
{importTotal > 0 && (
<div className='grid gap-2'>
<div className='flex justify-between text-sm'>
<span>{analyzing ? t('analyzing') : t('importing')}</span>
<span>
{importProgress} / {importTotal}
</span>
</div>
<Progress value={(importProgress / importTotal) * 100} />
</div>
)}
</div>
<DialogFooter>
<Button variant='outline' onClick={() => setOpen(false)} disabled={loading}>
{t('cancel')}
</Button>
<Button onClick={handleImport} disabled={loading || !yamlContent}>
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}
{t('import')}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}
+212
View File
@@ -0,0 +1,212 @@
'use client';
import { ProTable, ProTableActions } from '@/components/pro-table';
import {
createRuleGroup,
deleteRuleGroup,
getRuleGroupList,
updateRuleGroup,
} from '@/services/admin/server';
import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button';
import { Switch } from '@workspace/ui/components/switch';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import Image from 'next/legacy/image';
import Link from 'next/link';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import ImportYamlRules from './import-yaml-rules';
import RuleForm from './rule-form';
export default function Page() {
const t = useTranslations('rules');
const [loading, setLoading] = useState(false);
const ref = useRef<ProTableActions>(null);
return (
<ProTable<API.ServerRuleGroup, { query: string }>
action={ref}
header={{
toolbar: (
<div className='flex gap-2'>
<Button variant='default' asChild>
<Link href='/template/rules.yml' target='_blank' download>
{t('downloadTemplate')}
</Link>
</Button>
<ImportYamlRules onImportSuccess={() => ref.current?.refresh()} />
<RuleForm<API.CreateRuleGroupRequest>
trigger={t('create')}
title={t('createRule')}
loading={loading}
onSubmit={async (values) => {
setLoading(true);
try {
await createRuleGroup({
name: values.name,
rules: values.rules || '',
enable: false,
tags: values.tags || [],
icon: values.icon || '',
});
toast.success(t('createSuccess'));
ref.current?.refresh();
setLoading(false);
return true;
} catch (error) {
setLoading(false);
return false;
}
}}
/>
</div>
),
}}
params={[
{
key: 'search',
placeholder: t('searchRule'),
},
]}
request={async (pagination, filters) => {
const { data } = await getRuleGroupList({
...pagination,
...filters,
});
return {
list: data.data?.list || [],
total: data.data?.total || 0,
};
}}
columns={[
{
accessorKey: 'enable',
header: t('enable'),
cell: ({ row }) => {
return (
<Switch
defaultChecked={row.getValue('enable')}
onCheckedChange={async (checked) => {
await updateRuleGroup({
...row.original,
enable: checked,
} as API.UpdateRuleGroupRequest);
ref.current?.refresh();
}}
/>
);
},
},
{
accessorKey: 'icon',
header: t('appIcon'),
cell: ({ row }) =>
row.getValue('icon') ? (
<Image
src={row.getValue('icon')}
alt={row.getValue('name')}
className='h-8 w-8 rounded-md'
width={32}
height={32}
/>
) : (
<div className='bg-muted flex h-8 w-8 items-center justify-center rounded-md'>
{row.original.name?.slice(0, 2)}
</div>
),
},
{
accessorKey: 'name',
header: t('name'),
},
{
accessorKey: 'tags',
header: t('tags'),
cell: ({ row }) => {
const tags = row.original.tags.filter((item) => item) || [];
if (!tags.length) return '--';
return (
<>
{tags.map((tag) => (
<Badge key={tag} variant='outline' className='mr-1'>
{tag}
</Badge>
))}
</>
);
},
},
{
accessorKey: 'created_at',
header: t('createdAt'),
cell: ({ row }) => formatDate(row.original.created_at),
},
]}
actions={{
render: (row) => [
<RuleForm<API.UpdateRuleGroupRequest>
key='edit'
trigger={t('edit')}
title={t('editRule')}
loading={loading}
initialValues={row}
onSubmit={async (values) => {
setLoading(true);
try {
await updateRuleGroup({
id: row.id,
name: values.name,
tags: values.tags,
rules: values.rules,
enable: row.enable,
icon: values.icon,
});
toast.success(t('updateSuccess'));
ref.current?.refresh();
setLoading(false);
return true;
} catch (error) {
setLoading(false);
return false;
}
}}
/>,
<ConfirmButton
key='delete'
trigger={<Button variant='destructive'>{t('delete')}</Button>}
title={t('confirmDelete')}
description={t('deleteWarning')}
onConfirm={async () => {
await deleteRuleGroup({ id: row.id });
toast.success(t('deleteSuccess'));
ref.current?.refresh();
}}
cancelText={t('cancel')}
confirmText={t('confirm')}
/>,
],
batchRender: (rows) => [
<ConfirmButton
key='delete'
trigger={<Button variant='destructive'>{t('delete')}</Button>}
title={t('confirmDelete')}
description={t('deleteWarning')}
onConfirm={async () => {
for (const row of rows) {
await deleteRuleGroup({ id: row.id });
}
toast.success(t('deleteSuccess'));
ref.current?.reset();
ref.current?.refresh();
}}
cancelText={t('cancel')}
confirmText={t('confirm')}
/>,
],
}}
/>
);
}
@@ -0,0 +1,232 @@
'use client';
import { getNodeTagList } from '@/services/admin/server';
import { zodResolver } from '@hookform/resolvers/zod';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Sheet,
SheetContent,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@workspace/ui/components/sheet';
import { Textarea } from '@workspace/ui/components/textarea';
import { Combobox } from '@workspace/ui/custom-components/combobox';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { Icon } from '@workspace/ui/custom-components/icon';
import { UploadImage } from '@workspace/ui/custom-components/upload-image';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
const formSchema = z.object({
name: z.string().min(1, { message: '请输入规则名称' }),
tags: z.array(z.string()).default([]),
rules: z.string().default(''),
icon: z.string().default(''),
});
interface RuleFormProps<T> {
onSubmit: (data: T) => Promise<boolean> | boolean;
initialValues?: T;
loading?: boolean;
trigger: string;
title: string;
}
export default function RuleForm<T extends Record<string, any>>({
onSubmit,
initialValues,
loading,
trigger,
title,
}: RuleFormProps<T>) {
const t = useTranslations('rules');
const [open, setOpen] = useState(false);
const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
...initialValues,
} as any,
});
useEffect(() => {
if (initialValues) {
form.reset(initialValues);
}
}, [form, initialValues]);
async function handleSubmit(data: { [x: string]: any }) {
const bool = await onSubmit(data as T);
if (bool) setOpen(false);
}
const { data: tags } = useQuery({
queryKey: ['getNodeTagList'],
queryFn: async () => {
const { data } = await getNodeTagList();
return data.data?.tags || [];
},
});
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<Button
onClick={() => {
form.reset();
setOpen(true);
}}
>
{trigger}
</Button>
</SheetTrigger>
<SheetContent className='w-[500px] max-w-full md:max-w-screen-md'>
<SheetHeader>
<SheetTitle>{title}</SheetTitle>
</SheetHeader>
<ScrollArea className='-mx-6 h-[calc(100vh-48px-36px-36px-env(safe-area-inset-top))]'>
<Form {...form}>
<form onSubmit={form.handleSubmit(handleSubmit)} className='space-y-4 px-6 pt-4'>
<FormField
control={form.control}
name='icon'
render={({ field }) => (
<FormItem>
<FormLabel>{t('appIcon')}</FormLabel>
<FormControl>
<EnhancedInput
placeholder={t('enterIconUrl')}
value={field.value}
suffix={
<UploadImage
className='bg-muted h-9 rounded-none border-none px-2'
onChange={(value) => {
form.setValue(field.name, value as string);
}}
/>
}
onValueChange={(value) => {
form.setValue(field.name, value);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='name'
render={({ field }) => (
<FormItem>
<FormLabel>{t('name')}</FormLabel>
<FormControl>
<EnhancedInput
placeholder={t('enterRuleName')}
value={field.value}
onValueChange={(value) => {
form.setValue(field.name, value);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='tags'
render={({ field }) => (
<FormItem>
<FormLabel>{t('tagsLabel')}</FormLabel>
<FormControl>
<Combobox<string, true>
multiple
placeholder={t('selectTags')}
value={field.value}
onChange={(value) => {
form.setValue(field.name, value);
}}
options={tags?.map((item: string) => ({
value: item,
label: item,
}))}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='rules'
render={({ field }) => (
<FormItem>
<FormLabel>{t('rulesLabel')}</FormLabel>
<FormControl>
<Textarea
placeholder={t('enterRules')}
value={field.value}
rows={10}
onChange={(e) => {
form.setValue(field.name, e.target.value);
}}
/>
</FormControl>
<div className='text-muted-foreground mt-1 text-xs'>
<pre>{t('rulesFormat')}</pre>
<div className='border-muted mt-2 space-y-1 border-l-2 pl-2'>
<p className='font-mono'>DOMAIN,example.com</p>
<p className='font-mono'>DOMAIN-SUFFIX,google.com,DIRECT</p>
<p className='font-mono'>DOMAIN-KEYWORD,amazon,REJECT</p>
<p className='font-mono'>IP-CIDR,192.168.0.0/16</p>
<p className='font-mono'>IP-CIDR6,2001:db8::/32,REJECT</p>
<p className='font-mono'>SRC-IP-CIDR,192.168.1.201/32</p>
<p className='font-mono'>GEOIP,CN,DIRECT</p>
<p className='font-mono'>GEOIP,US</p>
<p className='font-mono'>DST-PORT,80,DIRECT</p>
<p className='font-mono'>SRC-PORT,7777,REJECT</p>
<p className='font-mono'>PROCESS-NAME,telegram</p>
<p className='font-mono'>RULE-SET,netflix</p>
</div>
</div>
<FormMessage />
</FormItem>
)}
/>
</form>
</Form>
</ScrollArea>
<SheetFooter className='flex-row justify-end gap-2 pt-3'>
<Button
variant='outline'
disabled={loading}
onClick={() => {
setOpen(false);
}}
>
{t('cancel')}
</Button>
<Button disabled={loading} onClick={form.handleSubmit(handleSubmit)}>
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}
{t('confirm')}
</Button>
</SheetFooter>
</SheetContent>
</Sheet>
);
}
@@ -362,9 +362,10 @@ export default function NodeForm<T extends { [x: string]: any }>({
<EnhancedInput <EnhancedInput
{...field} {...field}
type='number' type='number'
placeholder='1-65535' step={1}
min={1} min={1}
max={65535} max={65535}
placeholder='1-65535'
onValueChange={(value) => { onValueChange={(value) => {
form.setValue(field.name, value); form.setValue(field.name, value);
}} }}
@@ -418,6 +419,9 @@ export default function NodeForm<T extends { [x: string]: any }>({
<EnhancedInput <EnhancedInput
{...field} {...field}
type='number' type='number'
step={1}
min={1}
max={65535}
placeholder='1-65535' placeholder='1-65535'
onValueChange={(value) => { onValueChange={(value) => {
form.setValue(field.name, value); form.setValue(field.name, value);
@@ -899,6 +903,7 @@ export default function NodeForm<T extends { [x: string]: any }>({
{ {
name: 'port', name: 'port',
type: 'number', type: 'number',
step: 1,
min: 1, min: 1,
max: 65535, max: 65535,
placeholder: t('form.relayPort'), placeholder: t('form.relayPort'),
+48 -35
View File
@@ -1,5 +1,11 @@
'use client'; 'use client';
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@workspace/ui/components/accordion';
import { Badge } from '@workspace/ui/components/badge'; import { Badge } from '@workspace/ui/components/badge';
import { Progress } from '@workspace/ui/components/progress'; import { Progress } from '@workspace/ui/components/progress';
import { ScrollArea } from '@workspace/ui/components/scroll-area'; import { ScrollArea } from '@workspace/ui/components/scroll-area';
@@ -11,6 +17,8 @@ import {
} from '@workspace/ui/components/tooltip'; } from '@workspace/ui/components/tooltip';
import { formatDate } from '@workspace/ui/utils'; import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { useState } from 'react';
import { UserSubscribeDetail } from '../user/user-detail';
export function formatPercentage(value: number): string { export function formatPercentage(value: number): string {
return `${value.toFixed(1)}%`; return `${value.toFixed(1)}%`;
@@ -18,25 +26,19 @@ export function formatPercentage(value: number): string {
export function NodeStatusCell({ status }: { status: API.NodeStatus }) { export function NodeStatusCell({ status }: { status: API.NodeStatus }) {
const t = useTranslations('server.node'); const t = useTranslations('server.node');
const [openItem, setOpenItem] = useState<string | null>(null);
const { const { online, cpu, mem, disk, updated_at } = status || {
last_at, online: {},
online_users, cpu: 0,
status: serverStatus, mem: 0,
} = status || { disk: 0,
online_users: [], updated_at: 0,
status: {
cpu: 0,
mem: 0,
disk: 0,
updated_at: 0,
},
last_at: 0,
}; };
const isOnline = last_at > 0; const isOnline = updated_at > 0;
const badgeVariant = isOnline ? 'default' : 'destructive'; const badgeVariant = isOnline ? 'default' : 'destructive';
const badgeText = isOnline ? t('normal') : t('abnormal'); const badgeText = isOnline ? t('normal') : t('abnormal');
const onlineCount = Array.isArray(online_users) ? online_users?.length : 0; const onlineCount = (online && Object.keys(online).length) || 0;
return ( return (
<TooltipProvider> <TooltipProvider>
@@ -52,45 +54,56 @@ export function NodeStatusCell({ status }: { status: API.NodeStatus }) {
<div className='flex flex-col space-y-1'> <div className='flex flex-col space-y-1'>
<div className='flex justify-between'> <div className='flex justify-between'>
<span>CPU</span> <span>CPU</span>
<span>{formatPercentage(serverStatus?.cpu ?? 0)}</span> <span>{formatPercentage(cpu ?? 0)}</span>
</div> </div>
<Progress value={serverStatus?.cpu ?? 0} className='h-2' max={100} /> <Progress value={cpu ?? 0} className='h-2' max={100} />
</div> </div>
<div className='flex flex-col space-y-1'> <div className='flex flex-col space-y-1'>
<div className='flex justify-between'> <div className='flex justify-between'>
<span>{t('memory')}</span> <span>{t('memory')}</span>
<span>{formatPercentage(serverStatus?.mem ?? 0)}</span> <span>{formatPercentage(mem ?? 0)}</span>
</div> </div>
<Progress value={serverStatus?.mem ?? 0} className='h-2' max={100} /> <Progress value={mem ?? 0} className='h-2' max={100} />
</div> </div>
<div className='flex flex-col space-y-1'> <div className='flex flex-col space-y-1'>
<div className='flex justify-between'> <div className='flex justify-between'>
<span>{t('disk')}</span> <span>{t('disk')}</span>
<span>{formatPercentage(serverStatus?.disk ?? 0)}</span> <span>{formatPercentage(disk ?? 0)}</span>
</div> </div>
<Progress value={serverStatus?.disk ?? 0} className='h-2' max={100} /> <Progress value={disk ?? 0} className='h-2' max={100} />
</div> </div>
{isOnline && ( {isOnline && (
<div> <div>
{t('lastUpdated')}: {formatDate(serverStatus?.updated_at ?? 0)} {t('lastUpdated')}: {formatDate(updated_at ?? 0)}
</div> </div>
)} )}
</div> </div>
</TooltipTrigger> </TooltipTrigger>
{isOnline && onlineCount > 0 && ( {isOnline && onlineCount > 0 && (
<TooltipContent className='bg-muted text-foreground w-80'> <TooltipContent className='bg-card text-foreground w-96'>
<div className='space-y-4'> <ScrollArea className='h-[540px] rounded-md border px-4 py-2'>
<div className='space-y-2'> <h4 className='py-1 text-sm font-semibold'>{t('onlineUsers')}</h4>
<h4 className='text-sm font-semibold'>{t('onlineUsers')}</h4> <Accordion
<ScrollArea className='h-[400px] rounded-md border p-2'> type='single'
{online_users.map((user, index) => ( collapsible
<div key={user.uid} className='py-1 text-xs'> className='w-full'
{user.ip} (UID: {user.uid}) onValueChange={(value) => setOpenItem(value)}
</div> >
))} {Object.entries(online).map(([uid, ips]) => (
</ScrollArea> <AccordionItem key={uid} value={uid}>
</div> <AccordionTrigger>{`[UID: ${uid}] - ${ips[0]}`}</AccordionTrigger>
</div> <AccordionContent>
<ul>
{ips.map((ip: string) => (
<li key={ip}>{ip}</li>
))}
</ul>
<UserSubscribeDetail id={Number(uid)} enabled={openItem === uid} />
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</ScrollArea>
</TooltipContent> </TooltipContent>
)} )}
</Tooltip> </Tooltip>
@@ -2,7 +2,6 @@ import { getTranslations } from 'next-intl/server';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import SubscribeApp from './app/table';
import GroupTable from './group/table'; import GroupTable from './group/table';
import SubscribeConfig from './subscribe-config'; import SubscribeConfig from './subscribe-config';
import SubscribeTable from './subscribe-table'; import SubscribeTable from './subscribe-table';
@@ -16,7 +15,6 @@ export default async function Page() {
<TabsTrigger value='subscribe'>{t('tabs.subscribe')}</TabsTrigger> <TabsTrigger value='subscribe'>{t('tabs.subscribe')}</TabsTrigger>
<TabsTrigger value='group'>{t('tabs.subscribeGroup')}</TabsTrigger> <TabsTrigger value='group'>{t('tabs.subscribeGroup')}</TabsTrigger>
<TabsTrigger value='config'>{t('tabs.subscribeConfig')}</TabsTrigger> <TabsTrigger value='config'>{t('tabs.subscribeConfig')}</TabsTrigger>
<TabsTrigger value='app'>{t('tabs.subscribeApp')}</TabsTrigger>
</TabsList> </TabsList>
<TabsContent value='subscribe'> <TabsContent value='subscribe'>
<SubscribeTable /> <SubscribeTable />
@@ -27,9 +25,6 @@ export default async function Page() {
<TabsContent value='config'> <TabsContent value='config'>
<SubscribeConfig /> <SubscribeConfig />
</TabsContent> </TabsContent>
<TabsContent value='app'>
<SubscribeApp />
</TabsContent>
</Tabs> </Tabs>
); );
} }
@@ -157,6 +157,32 @@ export default function SubscribeForm<T extends Record<string, any>>({
}); });
const unit_time = form.watch('unit_time'); const unit_time = form.watch('unit_time');
const unit_price = form.watch('unit_price');
const discounts = form.watch('discount');
useEffect(() => {
if (!discounts?.length || !unit_price) return;
const calculatedValues = discounts.map((item: any) => {
const result = { ...item };
if (item.quantity && item.discount) {
result.price = evaluateWithPrecision(
`${unit_price || 0} * ${item.quantity} * ${item.discount} / 100`,
);
} else if (item.quantity && item.price && !item.discount) {
result.discount = evaluateWithPrecision(
`${item.price} / ${item.quantity} / ${unit_price} * 100`,
);
}
return result;
});
if (JSON.stringify(calculatedValues) !== JSON.stringify(discounts)) {
form.setValue('discount', calculatedValues);
}
}, [unit_price, discounts, form]);
return ( return (
<Sheet open={open} onOpenChange={setOpen}> <Sheet open={open} onOpenChange={setOpen}>
@@ -298,6 +324,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
<EnhancedInput <EnhancedInput
placeholder={t('form.noLimit')} placeholder={t('form.noLimit')}
type='number' type='number'
step={1}
{...field} {...field}
onValueChange={(value) => { onValueChange={(value) => {
form.setValue(field.name, value); form.setValue(field.name, value);
@@ -321,7 +348,8 @@ export default function SubscribeForm<T extends Record<string, any>>({
<EnhancedInput <EnhancedInput
placeholder={t('form.noLimit')} placeholder={t('form.noLimit')}
type='number' type='number'
value={field.value === -1 ? 0 : field.value} step={1}
value={field.value}
min={0} min={0}
onValueChange={(value) => { onValueChange={(value) => {
form.setValue(field.name, value); form.setValue(field.name, value);
@@ -343,6 +371,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
<EnhancedInput <EnhancedInput
placeholder={t('form.noLimit')} placeholder={t('form.noLimit')}
type='number' type='number'
step={1}
{...field} {...field}
onValueChange={(value) => { onValueChange={(value) => {
form.setValue(field.name, value); form.setValue(field.name, value);
@@ -540,11 +569,12 @@ export default function SubscribeForm<T extends Record<string, any>>({
<FormItem> <FormItem>
<FormLabel>{t('form.discount')}</FormLabel> <FormLabel>{t('form.discount')}</FormLabel>
<FormControl> <FormControl>
<ArrayInput<API.SubscribeDiscount> <ArrayInput<API.SubscribeDiscount & { price?: number }>
fields={[ fields={[
{ {
name: 'quantity', name: 'quantity',
type: 'number', type: 'number',
step: 1,
min: 1, min: 1,
suffix: unit_time && t(`form.${unit_time}`), suffix: unit_time && t(`form.${unit_time}`),
}, },
@@ -555,38 +585,56 @@ export default function SubscribeForm<T extends Record<string, any>>({
max: 100, max: 100,
placeholder: t('form.discountPercent'), placeholder: t('form.discountPercent'),
suffix: '%', suffix: '%',
calculateValue: function (data) {
const { unit_price } = form.getValues();
return {
...data,
price: evaluateWithPrecision(
`${unit_price} * ${data.quantity} * ${data.discount} / 100`,
),
};
},
}, },
{ {
name: 'price', name: 'price',
placeholder: t('form.discount_price'), placeholder: t('form.discount_price'),
type: 'number', type: 'number',
min: 0,
formatInput: (value) => unitConversion('centsToDollars', value), formatInput: (value) => unitConversion('centsToDollars', value),
formatOutput: (value) => unitConversion('dollarsToCents', value), formatOutput: (value) => unitConversion('dollarsToCents', value),
internal: true,
calculateValue: (data) => {
const { unit_price } = form.getValues();
return {
...data,
discount: evaluateWithPrecision(
`${data.price} / ${data.quantity} / ${unit_price} * 100`,
),
};
},
}, },
]} ]}
value={field.value} value={field.value}
onChange={(value) => { onChange={(newValues) => {
form.setValue(field.name, value); const oldValues = field.value || [];
const { unit_price } = form.getValues();
const calculatedValues = newValues.map((newItem, index) => {
const oldItem = oldValues[index] || {};
const result = { ...newItem };
const quantityChanged = newItem.quantity !== oldItem.quantity;
const discountChanged = newItem.discount !== oldItem.discount;
const priceChanged = newItem.price !== oldItem.price;
if (
(quantityChanged || discountChanged) &&
!priceChanged &&
newItem.quantity &&
newItem.discount
) {
result.price = evaluateWithPrecision(
`${unit_price || 0} * ${newItem.quantity} * ${newItem.discount} / 100`,
);
}
if (
priceChanged &&
!discountChanged &&
newItem.price &&
newItem.quantity &&
unit_price
) {
result.discount = evaluateWithPrecision(
`${newItem.price} / ${newItem.quantity} / ${unit_price} * 100`,
);
}
return result;
});
form.setValue(field.name, calculatedValues);
}} }}
/> />
</FormControl> </FormControl>
+48 -2
View File
@@ -5,18 +5,21 @@ import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label'; import { Label } from '@workspace/ui/components/label';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table'; import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { Textarea } from '@workspace/ui/components/textarea'; import { Textarea } from '@workspace/ui/components/textarea';
import { JSONEditor } from '@workspace/ui/custom-components/editor';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input'; import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { UploadImage } from '@workspace/ui/custom-components/upload-image'; import { UploadImage } from '@workspace/ui/custom-components/upload-image';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { useRef } from 'react';
import { toast } from 'sonner'; import { toast } from 'sonner';
export default function Site() { export default function Site() {
const t = useTranslations('system.site'); const t = useTranslations('system.site');
const ref = useRef<API.SiteConfig | undefined>(undefined);
const { data, refetch } = useQuery({ const { data, refetch } = useQuery({
queryKey: ['getSiteConfig'], queryKey: ['getSiteConfig'],
queryFn: async () => { queryFn: async () => {
const { data } = await getSiteConfig(); const { data } = await getSiteConfig();
ref.current = data.data;
return data.data; return data.data;
}, },
}); });
@@ -25,7 +28,7 @@ export default function Site() {
if (data?.[key] === value) return; if (data?.[key] === value) return;
try { try {
await updateSiteConfig({ await updateSiteConfig({
...data, ...ref.current,
[key]: value, [key]: value,
} as API.SiteConfig); } as API.SiteConfig);
toast.success(t('saveSuccess')); toast.success(t('saveSuccess'));
@@ -130,6 +133,49 @@ export default function Site() {
/> />
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow>
<TableCell>
<Label>{t('customData')}</Label>
<p className='text-muted-foreground text-xs'>{t('customDataDescription')}</p>
</TableCell>
<TableCell className='w-1/2 text-right'>
<JSONEditor
schema={{
type: 'object',
additionalProperties: true,
properties: {
website: { type: 'string', title: 'Website' },
contacts: {
type: 'object',
title: 'Contacts',
additionalProperties: true,
properties: {
email: { type: 'string', title: 'Email' },
telephone: { type: 'string', title: 'Telephone' },
address: { type: 'string', title: 'Address' },
},
},
community: {
type: 'object',
title: 'Community',
additionalProperties: true,
properties: {
telegram: { type: 'string', title: 'Telegram' },
twitter: { type: 'string', title: 'Twitter' },
discord: { type: 'string', title: 'Discord' },
instagram: { type: 'string', title: 'Instagram' },
linkedin: { type: 'string', title: 'Linkedin' },
facebook: { type: 'string', title: 'Facebook' },
github: { type: 'string', title: 'Github' },
},
},
},
}}
value={data?.custom_data}
onBlur={(value) => updateConfig('custom_data', value)}
/>
</TableCell>
</TableRow>
</TableBody> </TableBody>
</Table> </Table>
); );
+4 -5
View File
@@ -10,7 +10,6 @@ import {
} from '@workspace/ui/components/accordion'; } from '@workspace/ui/components/accordion';
import { import {
AlertDialog, AlertDialog,
AlertDialogAction,
AlertDialogCancel, AlertDialogCancel,
AlertDialogContent, AlertDialogContent,
AlertDialogDescription, AlertDialogDescription,
@@ -67,7 +66,7 @@ export default function Page() {
<CardDescription>{t('viewLogsAndManage')}</CardDescription> <CardDescription>{t('viewLogsAndManage')}</CardDescription>
</div> </div>
<div className='mt-4 flex flex-col space-y-2 sm:mt-0 sm:flex-row sm:space-x-2 sm:space-y-0'> <div className='mt-4 flex flex-col space-y-2 sm:mt-0 sm:flex-row sm:space-x-2 sm:space-y-0'>
<AlertDialog> {/* <AlertDialog>
<AlertDialogTrigger asChild> <AlertDialogTrigger asChild>
<Button>{t('systemUpgrade')}</Button> <Button>{t('systemUpgrade')}</Button>
</AlertDialogTrigger> </AlertDialogTrigger>
@@ -81,7 +80,7 @@ export default function Page() {
<AlertDialogAction>{t('confirmUpgrade')}</AlertDialogAction> <AlertDialogAction>{t('confirmUpgrade')}</AlertDialogAction>
</AlertDialogFooter> </AlertDialogFooter>
</AlertDialogContent> </AlertDialogContent>
</AlertDialog> </AlertDialog> */}
<AlertDialog open={openRestart} onOpenChange={setOpenRestart}> <AlertDialog open={openRestart} onOpenChange={setOpenRestart}>
<AlertDialogTrigger asChild> <AlertDialogTrigger asChild>
<Button variant='destructive'>{t('systemReboot')}</Button> <Button variant='destructive'>{t('systemReboot')}</Button>
@@ -113,14 +112,14 @@ export default function Page() {
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className='space-y-6'> <div className='space-y-6'>
<div className='flex items-center justify-between'> {/* <div className='flex items-center justify-between'>
<div className='text-lg font-semibold'> <div className='text-lg font-semibold'>
{t('currentVersion')} <span>V1.0.0</span> {t('currentVersion')} <span>V1.0.0</span>
</div> </div>
<div className='text-muted-foreground text-sm'> <div className='text-muted-foreground text-sm'>
{t('lastUpdated')} <span>2024-12-16 12:00:00</span> {t('lastUpdated')} <span>2024-12-16 12:00:00</span>
</div> </div>
</div> </div> */}
<Card className='overflow-hidden'> <Card className='overflow-hidden'>
<CardHeader className='bg-secondary py-1'> <CardHeader className='bg-secondary py-1'>
<div className='flex items-center justify-between'> <div className='flex items-center justify-between'>
@@ -113,6 +113,7 @@ export function BasicInfoForm({ user, refetch }: { user: API.User; refetch: () =
<FormControl> <FormControl>
<EnhancedInput <EnhancedInput
type='number' type='number'
min={0}
value={field.value} value={field.value}
prefix={currency?.currency_symbol ?? '$'} prefix={currency?.currency_symbol ?? '$'}
formatInput={(value) => unitConversion('centsToDollars', value)} formatInput={(value) => unitConversion('centsToDollars', value)}
@@ -136,6 +137,7 @@ export function BasicInfoForm({ user, refetch }: { user: API.User; refetch: () =
<FormControl> <FormControl>
<EnhancedInput <EnhancedInput
type='number' type='number'
min={0}
value={field.value} value={field.value}
prefix={currency?.currency_symbol ?? '$'} prefix={currency?.currency_symbol ?? '$'}
formatInput={(value) => unitConversion('centsToDollars', value)} formatInput={(value) => unitConversion('centsToDollars', value)}
@@ -159,6 +161,7 @@ export function BasicInfoForm({ user, refetch }: { user: API.User; refetch: () =
<FormControl> <FormControl>
<EnhancedInput <EnhancedInput
type='number' type='number'
min={0}
value={field.value} value={field.value}
prefix={currency?.currency_symbol ?? '$'} prefix={currency?.currency_symbol ?? '$'}
formatInput={(value) => unitConversion('centsToDollars', value)} formatInput={(value) => unitConversion('centsToDollars', value)}
+55 -4
View File
@@ -2,7 +2,9 @@
import { Display } from '@/components/display'; import { Display } from '@/components/display';
import { ProTable, ProTableActions } from '@/components/pro-table'; import { ProTable, ProTableActions } from '@/components/pro-table';
import { getSubscribeList } from '@/services/admin/subscribe';
import { createUser, deleteUser, getUserList, updateUserBasicInfo } from '@/services/admin/user'; import { createUser, deleteUser, getUserList, updateUserBasicInfo } from '@/services/admin/user';
import { useQuery } from '@tanstack/react-query';
import { Badge } from '@workspace/ui/components/badge'; import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button'; import { Button } from '@workspace/ui/components/button';
import { Switch } from '@workspace/ui/components/switch'; import { Switch } from '@workspace/ui/components/switch';
@@ -20,8 +22,19 @@ export default function Page() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const ref = useRef<ProTableActions>(null); const ref = useRef<ProTableActions>(null);
const { data: subscribeList } = useQuery({
queryKey: ['getSubscribeList', 'all'],
queryFn: async () => {
const { data } = await getSubscribeList({
page: 1,
size: 9999,
});
return data.data?.list as API.SubscribeGroup[];
},
});
return ( return (
<ProTable<API.User, Record<string, unknown>> <ProTable<API.User, API.GetUserListParams>
action={ref} action={ref}
header={{ header={{
title: t('userList'), title: t('userList'),
@@ -58,8 +71,21 @@ export default function Page() {
<Switch <Switch
defaultChecked={row.getValue('enable')} defaultChecked={row.getValue('enable')}
onCheckedChange={async (checked) => { onCheckedChange={async (checked) => {
const {
auth_methods,
user_devices,
enable_balance_notify,
enable_login_notify,
enable_subscribe_notify,
enable_trade_notify,
updated_at,
created_at,
id,
...rest
} = row.original;
await updateUserBasicInfo({ await updateUserBasicInfo({
...row.original, user_id: id,
...rest,
enable: checked, enable: checked,
} as unknown as API.UpdateUserBasiceInfoRequest); } as unknown as API.UpdateUserBasiceInfoRequest);
toast.success(t('updateSuccess')); toast.success(t('updateSuccess'));
@@ -119,13 +145,38 @@ export default function Page() {
cell: ({ row }) => formatDate(row.getValue('created_at')), cell: ({ row }) => formatDate(row.getValue('created_at')),
}, },
]} ]}
request={async (pagination) => { request={async (pagination, filter) => {
const { data } = await getUserList(pagination); const { data } = await getUserList({
...pagination,
...filter,
});
return { return {
list: data.data?.list || [], list: data.data?.list || [],
total: data.data?.total || 0, total: data.data?.total || 0,
}; };
}} }}
params={[
{
key: 'subscribe_id',
placeholder: t('subscription'),
options: subscribeList?.map((item) => ({
label: item.name,
value: String(item.id),
})),
},
{
key: 'search',
placeholder: 'Search',
},
{
key: 'user_id',
placeholder: t('userId'),
},
{
key: 'user_subscribe_id',
placeholder: t('subscriptionId'),
},
]}
actions={{ actions={{
render: (row) => { render: (row) => {
return [ return [
+108 -2
View File
@@ -1,15 +1,121 @@
'use client'; 'use client';
import { Display } from '@/components/display'; import { Display } from '@/components/display';
import { getUserDetail } from '@/services/admin/user'; import { getUserDetail, getUserSubscribeById } from '@/services/admin/user';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button'; import { Button } from '@workspace/ui/components/button';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@workspace/ui/components/hover-card'; import { HoverCard, HoverCardContent, HoverCardTrigger } from '@workspace/ui/components/hover-card';
import { formatDate } from '@workspace/ui/utils'; import { formatBytes, formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import Link from 'next/link'; import Link from 'next/link';
import { useState } from 'react'; import { useState } from 'react';
export function UserSubscribeDetail({ id, enabled }: { id: number; enabled: boolean }) {
const t = useTranslations('user');
const { data } = useQuery({
enabled: id !== 0 && enabled,
queryKey: ['getUserSubscribeById', id],
queryFn: async () => {
const { data } = await getUserSubscribeById({ id });
return data.data;
},
});
if (!id) return '--';
const usedTraffic = data ? data.upload + data.download : 0;
const totalTraffic = data?.traffic || 0;
return (
<div className='space-y-4'>
<div>
<h3 className='mb-2 text-sm font-medium'>{t('subscriptionInfo')}</h3>
<div className='bg-muted/30 rounded-lg p-3'>
<ul className='grid gap-3'>
<li className='flex items-center justify-between font-semibold'>
<span className='text-muted-foreground'>{t('subscriptionId')}</span>
<span>{data?.id || '--'}</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>{t('subscriptionName')}</span>
<span>{data?.subscribe?.name || '--'}</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>{t('token')}</span>
<div className='font-mono text-xs' title={data?.token || ''}>
{data?.token || '--'}
</div>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>{t('trafficUsage')}</span>
<span>
{data
? totalTraffic === 0
? `${formatBytes(usedTraffic)} / ${t('unlimited')}`
: `${formatBytes(usedTraffic)} / ${formatBytes(totalTraffic)}`
: '--'}
</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>{t('startTime')}</span>
<span>{data?.start_time ? formatDate(data.start_time) : '--'}</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>{t('expireTime')}</span>
<span>{data?.expire_time ? formatDate(data.expire_time) : '--'}</span>
</li>
</ul>
</div>
</div>
<div>
<h3 className='mb-2 text-sm font-medium'>
{t('userInfo')}
{data?.user_id && (
<Button
variant='link'
size='sm'
className='text-primary ml-2 h-auto p-0 text-xs'
asChild
>
<Link href={`/dashboard/user/${data.user_id}`}>{t('viewDetails')}</Link>
</Button>
)}
</h3>
<ul className='grid gap-3'>
<li className='flex items-center justify-between font-semibold'>
<span className='text-muted-foreground'>{t('userId')}</span>
<span>{data?.user_id}</span>
</li>
<li className='flex items-center justify-between font-semibold'>
<span className='text-muted-foreground'>{t('balance')}</span>
<span>
<Display type='currency' value={data?.user.balance} />
</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>{t('giftAmount')}</span>
<span>
<Display type='currency' value={data?.user?.gift_amount} />
</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>{t('commission')}</span>
<span>
<Display type='currency' value={data?.user?.commission} />
</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>{t('createdAt')}</span>
<span>{data?.user?.created_at && formatDate(data?.user?.created_at)}</span>
</li>
</ul>
</div>
</div>
);
}
export function UserDetail({ id }: { id: number }) { export function UserDetail({ id }: { id: number }) {
const t = useTranslations('user'); const t = useTranslations('user');
const [shouldFetch, setShouldFetch] = useState(false); const [shouldFetch, setShouldFetch] = useState(false);
+17 -12
View File
@@ -1,5 +1,6 @@
'use client'; 'use client';
import { UserSubscribeDetail } from '@/app/dashboard/user/user-detail';
import { queryServerTotalData, queryTicketWaitReply } from '@/services/admin/console'; import { queryServerTotalData, queryTicketWaitReply } from '@/services/admin/console';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card'; import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
@@ -11,6 +12,7 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from '@workspace/ui/components/select'; } from '@workspace/ui/components/select';
import { Separator } from '@workspace/ui/components/separator';
import { Tabs, TabsList, TabsTrigger } from '@workspace/ui/components/tabs'; import { Tabs, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { Icon } from '@workspace/ui/custom-components/icon'; import { Icon } from '@workspace/ui/custom-components/icon';
import { formatBytes } from '@workspace/ui/utils'; import { formatBytes } from '@workspace/ui/utils';
@@ -59,15 +61,13 @@ export default function Statistics() {
users: { users: {
today: today:
ServerTotal?.user_traffic_ranking_today?.map((item) => ({ ServerTotal?.user_traffic_ranking_today?.map((item) => ({
name: item.user_id, name: item.sid,
traffic: item.download + item.upload, traffic: item.download + item.upload,
email: item.email,
})) || [], })) || [],
yesterday: yesterday:
ServerTotal?.user_traffic_ranking_yesterday?.map((item) => ({ ServerTotal?.user_traffic_ranking_yesterday?.map((item) => ({
name: item.user_id, name: item.sid,
traffic: item.download + item.upload, traffic: item.download + item.upload,
email: item.email,
})) || [], })) || [],
}, },
}; };
@@ -175,10 +175,6 @@ export default function Statistics() {
label: t('type'), label: t('type'),
color: 'hsl(var(--muted))', color: 'hsl(var(--muted))',
}, },
email: {
label: t('email'),
color: 'hsl(var(--muted))',
},
label: { label: {
color: 'hsl(var(--foreground))', color: 'hsl(var(--foreground))',
}, },
@@ -204,13 +200,22 @@ export default function Statistics() {
tickFormatter={(value, index) => String(index + 1)} tickFormatter={(value, index) => String(index + 1)}
/> />
<ChartTooltip <ChartTooltip
trigger='hover'
content={ content={
<ChartTooltipContent <ChartTooltipContent
label={true} label={true}
labelFormatter={(label) => labelFormatter={(label, [payload]) =>
dataType === 'nodes' dataType === 'nodes' ? (
? `${t('nodes')}: ${label}` `${t('nodes')}: ${label}`
: `${t('users')}: ${label}` ) : (
<>
<div className='w-80'>
<UserSubscribeDetail id={payload?.payload.name} enabled={true} />
</div>
<Separator className='my-2' />
<div>{`${t('users')}: ${label}`}</div>
</>
)
} }
formatter={(value) => { formatter={(value) => {
return formatBytes(Number(value) || 0); return formatBytes(Number(value) || 0);
+15 -5
View File
@@ -81,16 +81,26 @@ export const navs = [
url: '/dashboard/server', url: '/dashboard/server',
icon: 'flat-color-icons:data-protection', icon: 'flat-color-icons:data-protection',
}, },
], {
}, title: 'Application Management',
{ url: '/dashboard/application',
title: 'Finance', icon: 'flat-color-icons:touchscreen-smartphone',
items: [ },
{
title: 'Rule Management',
url: '/dashboard/rules',
icon: 'flat-color-icons:ruler',
},
{ {
title: 'Subscribe Management', title: 'Subscribe Management',
url: '/dashboard/subscribe', url: '/dashboard/subscribe',
icon: 'flat-color-icons:shop', icon: 'flat-color-icons:shop',
}, },
],
},
{
title: 'Finance',
items: [
{ {
title: 'Order Management', title: 'Order Management',
url: '/dashboard/order', url: '/dashboard/order',
+1
View File
@@ -16,6 +16,7 @@ export const useGlobalStore = create<GlobalStore>((set) => ({
site_logo: '', site_logo: '',
keywords: '', keywords: '',
custom_html: '', custom_html: '',
custom_data: '',
}, },
verify: { verify: {
turnstile_site_key: '', turnstile_site_key: '',
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "Zadejte platnou e-mailovou adresu.", "email": "Zadejte platnou e-mailovou adresu.",
"existingAccount": "Již máte účet?", "existingAccount": "Již máte účet?",
"get": "Získat", "get": "Získat",
"invite": "Pozvánkový kód", "invite": "Pozvánkový kód (volitelné)",
"message": "#### Vážený uživateli,\n\nDěkujeme za váš zájem a podporu. V důsledku úpravy provozní strategie jsme uzavřeli registraci nových uživatelů. Během této doby nebude používání stávajících účtů nijak ovlivněno.\n\nSnažíme se vám poskytnout lepší služby a zážitky, a proto během uzavření registrace provedeme komplexní optimalizaci systému a aktualizaci funkcí. V budoucnu vás přivítáme s kvalitnějším obsahem a službami.\n\nSledujte naše webové stránky a sociální média pro nejnovější aktualizace a oznámení. Děkujeme za vaše pochopení a podporu.\n\nPokud máte jakékoli dotazy nebo potřebujete pomoc, neváhejte kontaktovat náš zákaznický servis.\n\n**Ještě jednou děkujeme za vaši podporu a pochopení.**", "message": "#### Vážený uživateli,\n\nDěkujeme za váš zájem a podporu. V důsledku úpravy provozní strategie jsme uzavřeli registraci nových uživatelů. Během této doby nebude používání stávajících účtů nijak ovlivněno.\n\nSnažíme se vám poskytnout lepší služby a zážitky, a proto během uzavření registrace provedeme komplexní optimalizaci systému a aktualizaci funkcí. V budoucnu vás přivítáme s kvalitnějším obsahem a službami.\n\nSledujte naše webové stránky a sociální média pro nejnovější aktualizace a oznámení. Děkujeme za vaše pochopení a podporu.\n\nPokud máte jakékoli dotazy nebo potřebujete pomoc, neváhejte kontaktovat náš zákaznický servis.\n\n**Ještě jednou děkujeme za vaši podporu a pochopení.**",
"passwordMismatch": "Hesla se neshodují", "passwordMismatch": "Hesla se neshodují",
"success": "Registrace úspěšná, automaticky přihlášeno!", "success": "Registrace úspěšná, automaticky přihlášeno!",
+2
View File
@@ -39,6 +39,8 @@
"status": "Stav", "status": "Stav",
"subject": "Předmět", "subject": "Předmět",
"template": "Šablona", "template": "Šablona",
"traffic_exceed_email_template": "Šablona oznámení o překročení provozu",
"traffic_exceed_email_templateDescription": "Zástupné symboly {after}.variable{before} budou nahrazeny skutečnými daty. Ujistěte se, že tyto proměnné zachováte.",
"verify_email_template": "Šablona ověřovacího e-mailu", "verify_email_template": "Šablona ověřovacího e-mailu",
"verify_email_templateDescription": "Zástupné symboly {after}.variable{before} budou nahrazeny skutečnými daty. Ujistěte se, že tyto proměnné zachováte.", "verify_email_templateDescription": "Zástupné symboly {after}.variable{before} budou nahrazeny skutečnými daty. Ujistěte se, že tyto proměnné zachováte.",
"whitelistSuffixes": "Povolené přípony", "whitelistSuffixes": "Povolené přípony",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "Konfigurace ADS", "ADS Config": "Konfigurace ADS",
"Announcement Management": "Správa oznámení", "Announcement Management": "Správa oznámení",
"Apple": "Apple ID", "Apple": "Apple ID",
"Application Management": "Správa aplikací",
"Auth Control": "Řízení ověřování", "Auth Control": "Řízení ověřování",
"Coupon Management": "Správa kupónů", "Coupon Management": "Správa kupónů",
"Dashboard": "Přístrojová deska", "Dashboard": "Přístrojová deska",
@@ -16,6 +17,7 @@
"Order Management": "Správa objednávek", "Order Management": "Správa objednávek",
"Payment Config": "Konfigurace platby", "Payment Config": "Konfigurace platby",
"Phone Number": "Telefonní číslo", "Phone Number": "Telefonní číslo",
"Rule Management": "Správa pravidel",
"Server": "Server", "Server": "Server",
"Server Management": "Správa serveru", "Server Management": "Správa serveru",
"Settings": "Nastavení", "Settings": "Nastavení",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "Analyzuji...",
"appIcon": "Ikona pravidla",
"cancel": "Zrušit",
"confirm": "Potvrdit",
"confirmDelete": "Potvrdit smazání",
"create": "Přidat pravidlo",
"createRule": "Přidat pravidlo",
"createSuccess": "Pravidlo bylo úspěšně vytvořeno",
"createdAt": "Vytvořeno dne",
"delete": "Smazat",
"deleteSuccess": "Pravidlo bylo úspěšně smazáno",
"deleteWarning": "Opravdu chcete smazat toto pravidlo? Tato akce není vratná.",
"description": "Popis pravidla",
"downloadTemplate": "Stáhnout šablonu",
"edit": "Upravit",
"editRule": "Upravit pravidlo",
"enable": "Povolit",
"enterIconUrl": "Zadejte nebo nahrajte ikonu",
"enterRuleName": "Zadejte název pravidla",
"enterRules": "Zadejte obsah pravidla, jedno na řádek",
"import": "Importovat",
"importFailed": "Import se nezdařil",
"importSuccess": "Import byl úspěšný",
"importYaml": "Importovat YAML",
"importYamlDescription": "Importujte pravidla ze souboru YAML, systém automaticky vytvoří skupiny pravidel na základě názvů skupin politiky",
"importYamlRules": "Importovat YAML pravidla",
"importing": "Importuji...",
"invalidYamlFormat": "Neplatný formát YAML, chybí pole pravidel",
"name": "Název pravidla",
"noValidRules": "Nebyly nalezeny žádné platné pravidla",
"pleaseUploadFile": "Prosím, nahrajte soubor YAML",
"preview": "Náhled",
"rules": "Obsah pravidla",
"rulesFormat": "Formát pravidla: typ pravidla, obsah shody, [politika], kde politika je volitelná.\nPokud politika není specifikována, bude automaticky použito aktuální jméno skupiny pravidel. Příklady:",
"rulesLabel": "Obsah pravidla",
"searchRule": "Hledat název pravidla",
"selectFile": "Vybrat soubor",
"selectTags": "Vybrat značky uzlu",
"tags": "Značky uzlu",
"tagsLabel": "Značky uzlu",
"updateSuccess": "Pravidlo bylo úspěšně aktualizováno"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "Zásady ochrany osobních údajů" "title": "Zásady ochrany osobních údajů"
}, },
"site": { "site": {
"customData": "Vlastní data",
"customDataDescription": "Vlastní data, používaná pro vlastní data webu",
"customHtml": "Vlastní HTML", "customHtml": "Vlastní HTML",
"customHtmlDescription": "Vlastní HTML kód, který bude vložen na konec tagu body na stránce.", "customHtmlDescription": "Vlastní HTML kód, který bude vložen na konec tagu body na stránce.",
"keywords": "Klíčová slova", "keywords": "Klíčová slova",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "Povolení účtu", "accountEnable": "Povolení účtu",
"actions": "akce", "actions": "akce",
"active": "Aktivní",
"add": "Přidat", "add": "Přidat",
"administrator": "Administrátor", "administrator": "Administrátor",
"areaCode": "Směrový kód", "areaCode": "Směrový kód",
@@ -41,10 +42,12 @@
"email": "e-mail", "email": "e-mail",
"enable": "Povolit", "enable": "Povolit",
"expireTime": "Čas vypršení", "expireTime": "Čas vypršení",
"expired": "Vypršelo",
"expiredAt": "Platnost vypršela", "expiredAt": "Platnost vypršela",
"failed": "Neúspěch", "failed": "Neúspěch",
"giftAmount": "Částka dárku", "giftAmount": "Částka dárku",
"giftAmountPlaceholder": "Zadejte částku dárku", "giftAmountPlaceholder": "Zadejte částku dárku",
"inactive": "Neaktivní",
"invalidEmailFormat": "Neplatný formát e-mailu", "invalidEmailFormat": "Neplatný formát e-mailu",
"inviteCode": "Pozvánkový kód", "inviteCode": "Pozvánkový kód",
"inviteCodePlaceholder": "Zadejte kód pozvánky (ponechte prázdné pro vygenerování)", "inviteCodePlaceholder": "Zadejte kód pozvánky (ponechte prázdné pro vygenerování)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "Zadejte nové heslo (volitelné)", "passwordPlaceholder": "Zadejte nové heslo (volitelné)",
"permanent": "Trvalý", "permanent": "Trvalý",
"pleaseEnterEmail": "Prosím, zadejte e-mail", "pleaseEnterEmail": "Prosím, zadejte e-mail",
"price": "Cena",
"referer": "Doporučitel", "referer": "Doporučitel",
"refererId": "ID doporučitele", "refererId": "ID doporučitele",
"refererIdPlaceholder": "Zadejte ID doporučitele", "refererIdPlaceholder": "Zadejte ID doporučitele",
@@ -74,8 +78,12 @@
"searchIp": "Vyhledat IP adresu", "searchIp": "Vyhledat IP adresu",
"selectAuthType": "Vyberte typ ověření", "selectAuthType": "Vyberte typ ověření",
"speedLimit": "Rychlostní limit", "speedLimit": "Rychlostní limit",
"startTime": "Čas zahájení",
"status": "Stav",
"subscription": "Předplatné", "subscription": "Předplatné",
"subscriptionDetails": "Podrobnosti o předplatném", "subscriptionDetails": "Podrobnosti o předplatném",
"subscriptionId": "ID předplatného",
"subscriptionInfo": "Informace o předplatném",
"subscriptionList": "Seznam předplatných", "subscriptionList": "Seznam předplatných",
"subscriptionLogs": "Záznamy o předplatném", "subscriptionLogs": "Záznamy o předplatném",
"subscriptionName": "Název předplatného", "subscriptionName": "Název předplatného",
@@ -89,6 +97,8 @@
"tradeNotifications": "Obchodní oznámení", "tradeNotifications": "Obchodní oznámení",
"trafficLimit": "Limit provozu", "trafficLimit": "Limit provozu",
"trafficLogs": "Protokoly provozu", "trafficLogs": "Protokoly provozu",
"trafficUsage": "Využití dat",
"unknown": "Neznámé",
"unlimited": "Neomezený", "unlimited": "Neomezený",
"unverified": "Neověřeno", "unverified": "Neověřeno",
"update": "Aktualizovat", "update": "Aktualizovat",
@@ -98,11 +108,15 @@
"userAgent": "Uživatelský agent", "userAgent": "Uživatelský agent",
"userEmail": "Uživatelský e-mail", "userEmail": "Uživatelský e-mail",
"userEmailPlaceholder": "Zadejte e-mail uživatele", "userEmailPlaceholder": "Zadejte e-mail uživatele",
"userId": "ID uživatele",
"userInfo": "Informace o uživateli",
"userList": "Seznam uživatelů", "userList": "Seznam uživatelů",
"userLogs": "Historie přihlášení", "userLogs": "Historie přihlášení",
"userName": "Identifikátor uživatele", "userName": "Identifikátor uživatele",
"userOrders": "Objednávky", "userOrders": "Objednávky",
"userProfile": "Profil", "userProfile": "Profil",
"userSubscriptions": "Předplatné", "userSubscriptions": "Předplatné",
"verified": "Ověřeno" "username": "Uživatelské jméno",
"verified": "Ověřeno",
"viewDetails": "Zobrazit podrobnosti"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "Bitte geben Sie eine gültige E-Mail-Adresse ein.", "email": "Bitte geben Sie eine gültige E-Mail-Adresse ein.",
"existingAccount": "Bereits ein Konto?", "existingAccount": "Bereits ein Konto?",
"get": "Erhalten", "get": "Erhalten",
"invite": "Einladungscode", "invite": "Einladungscode (optional)",
"message": "#### Sehr geehrter Nutzer,\n\nVielen Dank für Ihr Interesse und Ihre Unterstützung. Aufgrund einer Anpassung unserer Betriebsstrategie haben wir die Registrierung für neue Nutzer geschlossen. Während dieser Zeit wird die Nutzung für bestehende Nutzer nicht beeinträchtigt.\n\nWir sind bestrebt, Ihnen einen besseren Service und ein besseres Erlebnis zu bieten, und werden daher während der Schließung der Registrierung umfassende Systemoptimierungen und Funktionsupgrades durchführen. In Zukunft werden wir Sie mit hochwertigeren Inhalten und Dienstleistungen willkommen heißen.\n\nBitte folgen Sie unserer Website und unseren Social-Media-Plattformen, um die neuesten Updates und Benachrichtigungen zu erhalten. Vielen Dank für Ihr Verständnis und Ihre Unterstützung.\n\nBei Fragen oder wenn Sie Hilfe benötigen, kontaktieren Sie bitte jederzeit unser Kundenserviceteam.\n\n**Nochmals vielen Dank für Ihre Unterstützung und Ihr Verständnis.**", "message": "#### Sehr geehrter Nutzer,\n\nVielen Dank für Ihr Interesse und Ihre Unterstützung. Aufgrund einer Anpassung unserer Betriebsstrategie haben wir die Registrierung für neue Nutzer geschlossen. Während dieser Zeit wird die Nutzung für bestehende Nutzer nicht beeinträchtigt.\n\nWir sind bestrebt, Ihnen einen besseren Service und ein besseres Erlebnis zu bieten, und werden daher während der Schließung der Registrierung umfassende Systemoptimierungen und Funktionsupgrades durchführen. In Zukunft werden wir Sie mit hochwertigeren Inhalten und Dienstleistungen willkommen heißen.\n\nBitte folgen Sie unserer Website und unseren Social-Media-Plattformen, um die neuesten Updates und Benachrichtigungen zu erhalten. Vielen Dank für Ihr Verständnis und Ihre Unterstützung.\n\nBei Fragen oder wenn Sie Hilfe benötigen, kontaktieren Sie bitte jederzeit unser Kundenserviceteam.\n\n**Nochmals vielen Dank für Ihre Unterstützung und Ihr Verständnis.**",
"passwordMismatch": "Die eingegebenen Passwörter stimmen nicht überein", "passwordMismatch": "Die eingegebenen Passwörter stimmen nicht überein",
"success": "Registrierung erfolgreich, Sie sind automatisch eingeloggt!", "success": "Registrierung erfolgreich, Sie sind automatisch eingeloggt!",
+2
View File
@@ -39,6 +39,8 @@
"status": "Status", "status": "Status",
"subject": "Betreff", "subject": "Betreff",
"template": "Vorlage", "template": "Vorlage",
"traffic_exceed_email_template": "Benachrichtigung über überschreitenden Verkehr",
"traffic_exceed_email_templateDescription": "Die Platzhalter {after}.variable{before} werden durch tatsächliche Daten ersetzt. Stellen Sie sicher, dass Sie diese Variablen beibehalten.",
"verify_email_template": "E-Mail-Bestätigungsvorlage", "verify_email_template": "E-Mail-Bestätigungsvorlage",
"verify_email_templateDescription": "Die Platzhalter {after}.variable{before} werden durch tatsächliche Daten ersetzt. Stellen Sie sicher, dass diese Variablen beibehalten werden.", "verify_email_templateDescription": "Die Platzhalter {after}.variable{before} werden durch tatsächliche Daten ersetzt. Stellen Sie sicher, dass diese Variablen beibehalten werden.",
"whitelistSuffixes": "Whitelist-Suffixe", "whitelistSuffixes": "Whitelist-Suffixe",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "ADS-Konfiguration", "ADS Config": "ADS-Konfiguration",
"Announcement Management": "Ankündigungsverwaltung", "Announcement Management": "Ankündigungsverwaltung",
"Apple": "Apple-ID", "Apple": "Apple-ID",
"Application Management": "Anwendungsverwaltung",
"Auth Control": "Authentifizierungskontrolle", "Auth Control": "Authentifizierungskontrolle",
"Coupon Management": "Gutscheinverwaltung", "Coupon Management": "Gutscheinverwaltung",
"Dashboard": "Armaturenbrett", "Dashboard": "Armaturenbrett",
@@ -16,6 +17,7 @@
"Order Management": "Bestellverwaltung", "Order Management": "Bestellverwaltung",
"Payment Config": "Zahlungskonfiguration", "Payment Config": "Zahlungskonfiguration",
"Phone Number": "Telefonnummer", "Phone Number": "Telefonnummer",
"Rule Management": "Regelverwaltung",
"Server": "Dienst", "Server": "Dienst",
"Server Management": "Serververwaltung", "Server Management": "Serververwaltung",
"Settings": "Einstellungen", "Settings": "Einstellungen",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "Analysiere...",
"appIcon": "Regel-Icon",
"cancel": "Abbrechen",
"confirm": "Bestätigen",
"confirmDelete": "Löschen bestätigen",
"create": "Regel hinzufügen",
"createRule": "Regel hinzufügen",
"createSuccess": "Regel erfolgreich erstellt",
"createdAt": "Erstellt am",
"delete": "Löschen",
"deleteSuccess": "Regel erfolgreich gelöscht",
"deleteWarning": "Sind Sie sicher, dass Sie diese Regel löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.",
"description": "Regelbeschreibung",
"downloadTemplate": "Vorlage herunterladen",
"edit": "Bearbeiten",
"editRule": "Regel bearbeiten",
"enable": "Aktivieren",
"enterIconUrl": "Geben Sie eine URL für das Icon ein oder laden Sie es hoch",
"enterRuleName": "Geben Sie den Regelname ein",
"enterRules": "Geben Sie den Regelinhalt ein, jeweils eine Regel pro Zeile",
"import": "Importieren",
"importFailed": "Import fehlgeschlagen",
"importSuccess": "Import erfolgreich",
"importYaml": "YAML importieren",
"importYamlDescription": "Regeln aus einer YAML-Datei importieren, das System erstellt automatisch Regelgruppen basierend auf den Namen der Richtliniengruppen",
"importYamlRules": "YAML-Regeln importieren",
"importing": "Importiere...",
"invalidYamlFormat": "Ungültiges YAML-Format, das Feld 'Regeln' fehlt",
"name": "Regelname",
"noValidRules": "Keine gültigen Regeln gefunden",
"pleaseUploadFile": "Bitte laden Sie eine YAML-Datei hoch",
"preview": "Vorschau",
"rules": "Regelinhalt",
"rulesFormat": "Regelformat: Regeltyp, Übereinstimmungsinhalt, [Richtlinie], wobei die Richtlinie optional ist.\nWenn keine Richtlinie angegeben ist, wird automatisch der aktuelle Regelgruppenname verwendet. Beispiele:",
"rulesLabel": "Regelinhalt",
"searchRule": "Regelname suchen",
"selectFile": "Datei auswählen",
"selectTags": "Knoten-Tags auswählen",
"tags": "Knoten-Tags",
"tagsLabel": "Knoten-Tags",
"updateSuccess": "Regel erfolgreich aktualisiert"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "Datenschutzrichtlinie" "title": "Datenschutzrichtlinie"
}, },
"site": { "site": {
"customData": "Benutzerdefinierte Daten",
"customDataDescription": "Benutzerdefinierte Daten, die für benutzerdefinierte Daten der Website verwendet werden",
"customHtml": "Benutzerdefiniertes HTML", "customHtml": "Benutzerdefiniertes HTML",
"customHtmlDescription": "Benutzerdefinierter HTML-Code, der am Ende des body-Tags der Seite eingefügt werden soll.", "customHtmlDescription": "Benutzerdefinierter HTML-Code, der am Ende des body-Tags der Seite eingefügt werden soll.",
"keywords": "Schlüsselwörter", "keywords": "Schlüsselwörter",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "Konto aktivieren", "accountEnable": "Konto aktivieren",
"actions": "Aktionen", "actions": "Aktionen",
"active": "Aktiv",
"add": "Hinzufügen", "add": "Hinzufügen",
"administrator": "Administrator", "administrator": "Administrator",
"areaCode": "Vorwahl", "areaCode": "Vorwahl",
@@ -41,10 +42,12 @@
"email": "E-Mail", "email": "E-Mail",
"enable": "Aktivieren", "enable": "Aktivieren",
"expireTime": "Ablaufzeit", "expireTime": "Ablaufzeit",
"expired": "Abgelaufen",
"expiredAt": "Abgelaufen am", "expiredAt": "Abgelaufen am",
"failed": "Fehlgeschlagen", "failed": "Fehlgeschlagen",
"giftAmount": "Geschenkbetrag", "giftAmount": "Geschenkbetrag",
"giftAmountPlaceholder": "Geben Sie den Geschenkbetrag ein", "giftAmountPlaceholder": "Geben Sie den Geschenkbetrag ein",
"inactive": "Inaktiv",
"invalidEmailFormat": "Ungültiges E-Mail-Format", "invalidEmailFormat": "Ungültiges E-Mail-Format",
"inviteCode": "Einladungscode", "inviteCode": "Einladungscode",
"inviteCodePlaceholder": "Einladungscode eingeben (leer lassen, um zu generieren)", "inviteCodePlaceholder": "Einladungscode eingeben (leer lassen, um zu generieren)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "Neues Passwort eingeben (optional)", "passwordPlaceholder": "Neues Passwort eingeben (optional)",
"permanent": "Dauerhaft", "permanent": "Dauerhaft",
"pleaseEnterEmail": "Bitte E-Mail eingeben", "pleaseEnterEmail": "Bitte E-Mail eingeben",
"price": "Preis",
"referer": "Empfehler", "referer": "Empfehler",
"refererId": "Referenz-ID", "refererId": "Referenz-ID",
"refererIdPlaceholder": "Geben Sie die Referenz-ID ein", "refererIdPlaceholder": "Geben Sie die Referenz-ID ein",
@@ -74,8 +78,12 @@
"searchIp": "IP-Adresse suchen", "searchIp": "IP-Adresse suchen",
"selectAuthType": "Authentifizierungstyp auswählen", "selectAuthType": "Authentifizierungstyp auswählen",
"speedLimit": "Geschwindigkeitsbegrenzung", "speedLimit": "Geschwindigkeitsbegrenzung",
"startTime": "Startzeit",
"status": "Status",
"subscription": "Abonnement", "subscription": "Abonnement",
"subscriptionDetails": "Abonnementdetails", "subscriptionDetails": "Abonnementdetails",
"subscriptionId": "Abonnement-ID",
"subscriptionInfo": "Abonnement-Informationen",
"subscriptionList": "Abonnementsliste", "subscriptionList": "Abonnementsliste",
"subscriptionLogs": "Abonnementprotokolle", "subscriptionLogs": "Abonnementprotokolle",
"subscriptionName": "Abonnementname", "subscriptionName": "Abonnementname",
@@ -89,6 +97,8 @@
"tradeNotifications": "Handelsbenachrichtigungen", "tradeNotifications": "Handelsbenachrichtigungen",
"trafficLimit": "Verkehrslimit", "trafficLimit": "Verkehrslimit",
"trafficLogs": "Verkehrsprotokolle", "trafficLogs": "Verkehrsprotokolle",
"trafficUsage": "Datenverbrauch",
"unknown": "Unbekannt",
"unlimited": "Unbegrenzt", "unlimited": "Unbegrenzt",
"unverified": "Unbestätigt", "unverified": "Unbestätigt",
"update": "Aktualisieren", "update": "Aktualisieren",
@@ -98,11 +108,15 @@
"userAgent": "Benutzeragent", "userAgent": "Benutzeragent",
"userEmail": "Benutzer-E-Mail", "userEmail": "Benutzer-E-Mail",
"userEmailPlaceholder": "Benutzer-E-Mail eingeben", "userEmailPlaceholder": "Benutzer-E-Mail eingeben",
"userId": "Benutzer-ID",
"userInfo": "Benutzerinformationen",
"userList": "Benutzerliste", "userList": "Benutzerliste",
"userLogs": "Anmeldeverlauf", "userLogs": "Anmeldeverlauf",
"userName": "Benutzerkennung", "userName": "Benutzerkennung",
"userOrders": "Bestellungen", "userOrders": "Bestellungen",
"userProfile": "Profil", "userProfile": "Profil",
"userSubscriptions": "Abonnements", "userSubscriptions": "Abonnements",
"verified": "Verifiziert" "username": "Benutzername",
"verified": "Verifiziert",
"viewDetails": "Details anzeigen"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "Please enter a valid email address.", "email": "Please enter a valid email address.",
"existingAccount": "Already have an account?", "existingAccount": "Already have an account?",
"get": "Get", "get": "Get",
"invite": "Invitation code", "invite": "Invitation code (optional)",
"message": "#### Dear User, Hello!\n\nThank you for your attention and support. Due to adjustments in site operation strategy, we have closed the new user registration function. During this period, existing users will not be affected.\n\nWe are committed to providing you with better service and experience, so we will conduct comprehensive system optimization and feature upgrades during the registration closure. In the future, we will welcome you with better content and services.\n\nPlease follow our website and social media platforms to get the latest updates and notifications. Thank you for your understanding and support.\n\nIf you have any questions or need assistance, please feel free to contact our customer service team.\n\n**Thank you again for your support and understanding.**", "message": "#### Dear User, Hello!\n\nThank you for your attention and support. Due to adjustments in site operation strategy, we have closed the new user registration function. During this period, existing users will not be affected.\n\nWe are committed to providing you with better service and experience, so we will conduct comprehensive system optimization and feature upgrades during the registration closure. In the future, we will welcome you with better content and services.\n\nPlease follow our website and social media platforms to get the latest updates and notifications. Thank you for your understanding and support.\n\nIf you have any questions or need assistance, please feel free to contact our customer service team.\n\n**Thank you again for your support and understanding.**",
"passwordMismatch": "Passwords do not match", "passwordMismatch": "Passwords do not match",
"success": "Registration successful, automatically logged in!", "success": "Registration successful, automatically logged in!",
+2
View File
@@ -39,6 +39,8 @@
"status": "Status", "status": "Status",
"subject": "Subject", "subject": "Subject",
"template": "Template", "template": "Template",
"traffic_exceed_email_template": "Traffic Exceed Notice Template",
"traffic_exceed_email_templateDescription": "The {after}.variable{before} placeholders will be replaced with actual data. Ensure to keep these variables.",
"verify_email_template": "Verification Email Template", "verify_email_template": "Verification Email Template",
"verify_email_templateDescription": "The {after}.variable{before} placeholders will be replaced with actual data. Ensure to keep these variables.", "verify_email_templateDescription": "The {after}.variable{before} placeholders will be replaced with actual data. Ensure to keep these variables.",
"whitelistSuffixes": "Whitelist Suffixes", "whitelistSuffixes": "Whitelist Suffixes",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "ADS Config", "ADS Config": "ADS Config",
"Announcement Management": "Announcement Management", "Announcement Management": "Announcement Management",
"Apple": "Apple ID", "Apple": "Apple ID",
"Application Management": "Application Management",
"Auth Control": "Auth Control", "Auth Control": "Auth Control",
"Coupon Management": "Coupon Management", "Coupon Management": "Coupon Management",
"Dashboard": "Dashboard", "Dashboard": "Dashboard",
@@ -16,6 +17,7 @@
"Order Management": "Order Management", "Order Management": "Order Management",
"Payment Config": "Payment Config", "Payment Config": "Payment Config",
"Phone Number": "Phone Number", "Phone Number": "Phone Number",
"Rule Management": "Rule Management",
"Server": "Server", "Server": "Server",
"Server Management": "Server Management", "Server Management": "Server Management",
"Settings": "Settings", "Settings": "Settings",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "Analyzing...",
"appIcon": "Rule Icon",
"cancel": "Cancel",
"confirm": "Confirm",
"confirmDelete": "Confirm Deletion",
"create": "Add Rule",
"createRule": "Add Rule",
"createSuccess": "Rule created successfully",
"createdAt": "Created At",
"delete": "Delete",
"deleteSuccess": "Rule deleted successfully",
"deleteWarning": "Are you sure you want to delete this rule? This action cannot be undone.",
"description": "Rule Description",
"downloadTemplate": "Download Template",
"edit": "Edit",
"editRule": "Edit Rule",
"enable": "Enable",
"enterIconUrl": "Enter or upload an icon",
"enterRuleName": "Enter rule name",
"enterRules": "Enter rule content, one per line",
"import": "Import",
"importFailed": "Import failed",
"importSuccess": "Import successful",
"importYaml": "Import YAML",
"importYamlDescription": "Import rules from YAML file, the system will automatically create rule groups based on policy group names",
"importYamlRules": "Import YAML Rules",
"importing": "Importing...",
"invalidYamlFormat": "Invalid YAML format, missing rules field",
"name": "Rule Name",
"noValidRules": "No valid rules found",
"pleaseUploadFile": "Please upload a YAML file",
"preview": "Preview",
"rules": "Rule Content",
"rulesFormat": "Rule format: rule type,match content,[policy], where policy is optional.\nIf policy is not specified, the current rule group name will be used automatically. Examples:",
"rulesLabel": "Rule Content",
"searchRule": "Search rule name",
"selectFile": "Select File",
"selectTags": "Select node tags",
"tags": "Node Tags",
"tagsLabel": "Node Tags",
"updateSuccess": "Rule updated successfully"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "Privacy Policy" "title": "Privacy Policy"
}, },
"site": { "site": {
"customData": "Custom Data",
"customDataDescription": "Custom Data, used for custom data of the site",
"customHtml": "Custom HTML", "customHtml": "Custom HTML",
"customHtmlDescription": "Custom HTML code to be injected into the bottom of the site's body tag.", "customHtmlDescription": "Custom HTML code to be injected into the bottom of the site's body tag.",
"keywords": "Keywords", "keywords": "Keywords",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "Account Enable", "accountEnable": "Account Enable",
"actions": "Actions", "actions": "Actions",
"active": "Active",
"add": "Add", "add": "Add",
"administrator": "Administrator", "administrator": "Administrator",
"areaCode": "Area Code", "areaCode": "Area Code",
@@ -41,10 +42,12 @@
"email": "Email", "email": "Email",
"enable": "Enable", "enable": "Enable",
"expireTime": "Expire Time", "expireTime": "Expire Time",
"expired": "Expired",
"expiredAt": "Expired At", "expiredAt": "Expired At",
"failed": "Failed", "failed": "Failed",
"giftAmount": "Gift Amount", "giftAmount": "Gift Amount",
"giftAmountPlaceholder": "Enter gift amount", "giftAmountPlaceholder": "Enter gift amount",
"inactive": "Inactive",
"invalidEmailFormat": "Invalid email format", "invalidEmailFormat": "Invalid email format",
"inviteCode": "Invite Code", "inviteCode": "Invite Code",
"inviteCodePlaceholder": "Enter invite code (leave blank to generate)", "inviteCodePlaceholder": "Enter invite code (leave blank to generate)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "Enter new password (optional)", "passwordPlaceholder": "Enter new password (optional)",
"permanent": "Permanent", "permanent": "Permanent",
"pleaseEnterEmail": "Please enter email", "pleaseEnterEmail": "Please enter email",
"price": "Price",
"referer": "Referer", "referer": "Referer",
"refererId": "Referer ID", "refererId": "Referer ID",
"refererIdPlaceholder": "Enter referer ID", "refererIdPlaceholder": "Enter referer ID",
@@ -74,8 +78,12 @@
"searchIp": "Search IP address", "searchIp": "Search IP address",
"selectAuthType": "Select auth type", "selectAuthType": "Select auth type",
"speedLimit": "Speed Limit", "speedLimit": "Speed Limit",
"startTime": "Start Time",
"status": "Status",
"subscription": "Subscription", "subscription": "Subscription",
"subscriptionDetails": "Subscription Details", "subscriptionDetails": "Subscription Details",
"subscriptionId": "Subscription ID",
"subscriptionInfo": "Subscription Info",
"subscriptionList": "Subscription List", "subscriptionList": "Subscription List",
"subscriptionLogs": "Subscription Logs", "subscriptionLogs": "Subscription Logs",
"subscriptionName": "Subscription Name", "subscriptionName": "Subscription Name",
@@ -89,6 +97,8 @@
"tradeNotifications": "Trade Notifications", "tradeNotifications": "Trade Notifications",
"trafficLimit": "Traffic Limit", "trafficLimit": "Traffic Limit",
"trafficLogs": "Traffic Logs", "trafficLogs": "Traffic Logs",
"trafficUsage": "Traffic Usage",
"unknown": "Unknown",
"unlimited": "Unlimited", "unlimited": "Unlimited",
"unverified": "Unverified", "unverified": "Unverified",
"update": "Update", "update": "Update",
@@ -98,11 +108,15 @@
"userAgent": "User Agent", "userAgent": "User Agent",
"userEmail": "User Email", "userEmail": "User Email",
"userEmailPlaceholder": "Enter user email", "userEmailPlaceholder": "Enter user email",
"userId": "User ID",
"userInfo": "User Info",
"userList": "User List", "userList": "User List",
"userLogs": "Login History", "userLogs": "Login History",
"userName": "User Identifier", "userName": "User Identifier",
"userOrders": "Orders", "userOrders": "Orders",
"userProfile": "Profile", "userProfile": "Profile",
"userSubscriptions": "Subscriptions", "userSubscriptions": "Subscriptions",
"verified": "Verified" "username": "Username",
"verified": "Verified",
"viewDetails": "View Details"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "Por favor, introduce una dirección de correo electrónico válida.", "email": "Por favor, introduce una dirección de correo electrónico válida.",
"existingAccount": "¿Ya tienes una cuenta?", "existingAccount": "¿Ya tienes una cuenta?",
"get": "Obtener", "get": "Obtener",
"invite": "Código de invitación", "invite": "Código de invitación (opcional)",
"message": "#### ¡Estimado usuario!\n\nGracias por su interés y apoyo. Debido a un ajuste en la estrategia de operación del sitio, hemos cerrado la función de registro para nuevos usuarios. Durante este período, el uso por parte de los usuarios existentes no se verá afectado.\n\nNos comprometemos a brindarle un mejor servicio y experiencia, por lo que realizaremos una optimización completa del sistema y una actualización de funciones durante el cierre del registro. En el futuro, le daremos la bienvenida con contenido y servicios de mayor calidad.\n\nPor favor, siga nuestro sitio web y plataformas de redes sociales para obtener las últimas actualizaciones y notificaciones. Agradecemos su comprensión y apoyo.\n\nSi tiene alguna pregunta o necesita ayuda, no dude en ponerse en contacto con nuestro equipo de atención al cliente.\n\n**Nuevamente, gracias por su apoyo y comprensión.**", "message": "#### ¡Estimado usuario!\n\nGracias por su interés y apoyo. Debido a un ajuste en la estrategia de operación del sitio, hemos cerrado la función de registro para nuevos usuarios. Durante este período, el uso por parte de los usuarios existentes no se verá afectado.\n\nNos comprometemos a brindarle un mejor servicio y experiencia, por lo que realizaremos una optimización completa del sistema y una actualización de funciones durante el cierre del registro. En el futuro, le daremos la bienvenida con contenido y servicios de mayor calidad.\n\nPor favor, siga nuestro sitio web y plataformas de redes sociales para obtener las últimas actualizaciones y notificaciones. Agradecemos su comprensión y apoyo.\n\nSi tiene alguna pregunta o necesita ayuda, no dude en ponerse en contacto con nuestro equipo de atención al cliente.\n\n**Nuevamente, gracias por su apoyo y comprensión.**",
"passwordMismatch": "Las contraseñas no coinciden", "passwordMismatch": "Las contraseñas no coinciden",
"success": "¡Registro exitoso, sesión iniciada automáticamente!", "success": "¡Registro exitoso, sesión iniciada automáticamente!",
+2
View File
@@ -39,6 +39,8 @@
"status": "Estado", "status": "Estado",
"subject": "Asunto", "subject": "Asunto",
"template": "Plantilla", "template": "Plantilla",
"traffic_exceed_email_template": "Plantilla de Notificación de Exceso de Tráfico",
"traffic_exceed_email_templateDescription": "Los marcadores de posición {after}.variable{before} serán reemplazados con datos reales. Asegúrate de mantener estas variables.",
"verify_email_template": "Plantilla de Correo Electrónico de Verificación", "verify_email_template": "Plantilla de Correo Electrónico de Verificación",
"verify_email_templateDescription": "Los marcadores de posición {after}.variable{before} serán reemplazados con datos reales. Asegúrese de mantener estas variables.", "verify_email_templateDescription": "Los marcadores de posición {after}.variable{before} serán reemplazados con datos reales. Asegúrese de mantener estas variables.",
"whitelistSuffixes": "Sufijos de la lista blanca", "whitelistSuffixes": "Sufijos de la lista blanca",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "Configuración de ADS", "ADS Config": "Configuración de ADS",
"Announcement Management": "Gestión de Anuncios", "Announcement Management": "Gestión de Anuncios",
"Apple": "ID de Apple", "Apple": "ID de Apple",
"Application Management": "Gestión de Aplicaciones",
"Auth Control": "Control de Autenticación", "Auth Control": "Control de Autenticación",
"Coupon Management": "Gestión de Cupones", "Coupon Management": "Gestión de Cupones",
"Dashboard": "Tablero", "Dashboard": "Tablero",
@@ -16,6 +17,7 @@
"Order Management": "Gestión de Pedidos", "Order Management": "Gestión de Pedidos",
"Payment Config": "Configuración de Pago", "Payment Config": "Configuración de Pago",
"Phone Number": "Número de Teléfono", "Phone Number": "Número de Teléfono",
"Rule Management": "Gestión de Reglas",
"Server": "Servidor", "Server": "Servidor",
"Server Management": "Gestión de Servidores", "Server Management": "Gestión de Servidores",
"Settings": "Configuración", "Settings": "Configuración",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "Analizando...",
"appIcon": "Icono de Regla",
"cancel": "Cancelar",
"confirm": "Confirmar",
"confirmDelete": "Confirmar Eliminación",
"create": "Agregar Regla",
"createRule": "Agregar Regla",
"createSuccess": "Regla creada con éxito",
"createdAt": "Creado En",
"delete": "Eliminar",
"deleteSuccess": "Regla eliminada con éxito",
"deleteWarning": "¿Está seguro de que desea eliminar esta regla? Esta acción no se puede deshacer.",
"description": "Descripción de la Regla",
"downloadTemplate": "Descargar Plantilla",
"edit": "Editar",
"editRule": "Editar Regla",
"enable": "Habilitar",
"enterIconUrl": "Ingrese o suba un icono",
"enterRuleName": "Ingrese el nombre de la regla",
"enterRules": "Ingrese el contenido de la regla, uno por línea",
"import": "Importar",
"importFailed": "Importación fallida",
"importSuccess": "Importación exitosa",
"importYaml": "Importar YAML",
"importYamlDescription": "Importar reglas desde un archivo YAML, el sistema creará automáticamente grupos de reglas basados en los nombres de los grupos de políticas",
"importYamlRules": "Importar Reglas YAML",
"importing": "Importando...",
"invalidYamlFormat": "Formato YAML inválido, falta el campo de reglas",
"name": "Nombre de la Regla",
"noValidRules": "No se encontraron reglas válidas",
"pleaseUploadFile": "Por favor, suba un archivo YAML",
"preview": "Vista Previa",
"rules": "Contenido de la Regla",
"rulesFormat": "Formato de regla: tipo de regla, contenido de coincidencia, [política], donde la política es opcional.\nSi no se especifica la política, se utilizará automáticamente el nombre del grupo de reglas actual. Ejemplos:",
"rulesLabel": "Contenido de la Regla",
"searchRule": "Buscar nombre de regla",
"selectFile": "Seleccionar Archivo",
"selectTags": "Seleccionar etiquetas de nodo",
"tags": "Etiquetas de Nodo",
"tagsLabel": "Etiquetas de Nodo",
"updateSuccess": "Regla actualizada con éxito"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "Política de Privacidad" "title": "Política de Privacidad"
}, },
"site": { "site": {
"customData": "Datos Personalizados",
"customDataDescription": "Datos Personalizados, utilizados para datos personalizados del sitio",
"customHtml": "HTML personalizado", "customHtml": "HTML personalizado",
"customHtmlDescription": "Código HTML personalizado que se inyectará en la parte inferior de la etiqueta body del sitio.", "customHtmlDescription": "Código HTML personalizado que se inyectará en la parte inferior de la etiqueta body del sitio.",
"keywords": "Palabras clave", "keywords": "Palabras clave",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "Habilitar cuenta", "accountEnable": "Habilitar cuenta",
"actions": "acciones", "actions": "acciones",
"active": "Activo",
"add": "Agregar", "add": "Agregar",
"administrator": "Administrador", "administrator": "Administrador",
"areaCode": "Código de Área", "areaCode": "Código de Área",
@@ -41,10 +42,12 @@
"email": "correo electrónico", "email": "correo electrónico",
"enable": "Habilitar", "enable": "Habilitar",
"expireTime": "Tiempo de Expiración", "expireTime": "Tiempo de Expiración",
"expired": "Caducado",
"expiredAt": "Fecha de vencimiento", "expiredAt": "Fecha de vencimiento",
"failed": "Fallido", "failed": "Fallido",
"giftAmount": "Monto del Regalo", "giftAmount": "Monto del Regalo",
"giftAmountPlaceholder": "Ingrese el monto del regalo", "giftAmountPlaceholder": "Ingrese el monto del regalo",
"inactive": "Inactivo",
"invalidEmailFormat": "Formato de correo electrónico no válido", "invalidEmailFormat": "Formato de correo electrónico no válido",
"inviteCode": "Código de invitación", "inviteCode": "Código de invitación",
"inviteCodePlaceholder": "Introduce el código de invitación (déjalo en blanco para generar uno)", "inviteCodePlaceholder": "Introduce el código de invitación (déjalo en blanco para generar uno)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "Ingrese nueva contraseña (opcional)", "passwordPlaceholder": "Ingrese nueva contraseña (opcional)",
"permanent": "Permanente", "permanent": "Permanente",
"pleaseEnterEmail": "Por favor, introduce el correo electrónico", "pleaseEnterEmail": "Por favor, introduce el correo electrónico",
"price": "Precio",
"referer": "Recomendador", "referer": "Recomendador",
"refererId": "ID del Referente", "refererId": "ID del Referente",
"refererIdPlaceholder": "Ingrese el ID del referente", "refererIdPlaceholder": "Ingrese el ID del referente",
@@ -74,8 +78,12 @@
"searchIp": "Buscar dirección IP", "searchIp": "Buscar dirección IP",
"selectAuthType": "Seleccionar tipo de autenticación", "selectAuthType": "Seleccionar tipo de autenticación",
"speedLimit": "Límite de Velocidad", "speedLimit": "Límite de Velocidad",
"startTime": "Hora de Inicio",
"status": "Estado",
"subscription": "Suscripción", "subscription": "Suscripción",
"subscriptionDetails": "Detalles de la suscripción", "subscriptionDetails": "Detalles de la suscripción",
"subscriptionId": "ID de Suscripción",
"subscriptionInfo": "Información de Suscripción",
"subscriptionList": "Lista de Suscripción", "subscriptionList": "Lista de Suscripción",
"subscriptionLogs": "Registros de Suscripción", "subscriptionLogs": "Registros de Suscripción",
"subscriptionName": "Nombre de la Suscripción", "subscriptionName": "Nombre de la Suscripción",
@@ -89,6 +97,8 @@
"tradeNotifications": "Notificaciones de Comercio", "tradeNotifications": "Notificaciones de Comercio",
"trafficLimit": "Límite de Tráfico", "trafficLimit": "Límite de Tráfico",
"trafficLogs": "Registros de Tráfico", "trafficLogs": "Registros de Tráfico",
"trafficUsage": "Uso de Tráfico",
"unknown": "Desconocido",
"unlimited": "Ilimitado", "unlimited": "Ilimitado",
"unverified": "No verificado", "unverified": "No verificado",
"update": "Actualizar", "update": "Actualizar",
@@ -98,11 +108,15 @@
"userAgent": "Agente de Usuario", "userAgent": "Agente de Usuario",
"userEmail": "Correo Electrónico del Usuario", "userEmail": "Correo Electrónico del Usuario",
"userEmailPlaceholder": "Introduce el correo electrónico del usuario", "userEmailPlaceholder": "Introduce el correo electrónico del usuario",
"userId": "ID de Usuario",
"userInfo": "Información de Usuario",
"userList": "Lista de usuarios", "userList": "Lista de usuarios",
"userLogs": "Historial de inicio de sesión", "userLogs": "Historial de inicio de sesión",
"userName": "Identificador de Usuario", "userName": "Identificador de Usuario",
"userOrders": "Pedidos", "userOrders": "Pedidos",
"userProfile": "Perfil", "userProfile": "Perfil",
"userSubscriptions": "Suscripciones", "userSubscriptions": "Suscripciones",
"verified": "Verificado" "username": "Nombre de Usuario",
"verified": "Verificado",
"viewDetails": "Ver Detalles"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "Por favor, ingresa una dirección de correo electrónico válida.", "email": "Por favor, ingresa una dirección de correo electrónico válida.",
"existingAccount": "¿Ya tienes una cuenta?", "existingAccount": "¿Ya tienes una cuenta?",
"get": "Obtener", "get": "Obtener",
"invite": "Código de invitación", "invite": "Código de invitación (opcional)",
"message": "#### Estimado usuario,\n\nGracias por su interés y apoyo. Debido a un ajuste en la estrategia de operación del sitio, hemos cerrado la función de registro para nuevos usuarios. Durante este período, el uso por parte de los usuarios existentes no se verá afectado.\n\nNos comprometemos a ofrecerle un mejor servicio y experiencia, por lo que realizaremos una optimización completa del sistema y una actualización de funciones durante el cierre del registro. En el futuro, le daremos la bienvenida con contenido y servicios de mayor calidad.\n\nPor favor, siga nuestro sitio web y plataformas de redes sociales para obtener las últimas actualizaciones y notificaciones. Agradecemos su comprensión y apoyo.\n\nSi tiene alguna pregunta o necesita ayuda, no dude en ponerse en contacto con nuestro equipo de atención al cliente.\n\n**Nuevamente, gracias por su apoyo y comprensión.**", "message": "#### Estimado usuario,\n\nGracias por su interés y apoyo. Debido a un ajuste en la estrategia de operación del sitio, hemos cerrado la función de registro para nuevos usuarios. Durante este período, el uso por parte de los usuarios existentes no se verá afectado.\n\nNos comprometemos a ofrecerle un mejor servicio y experiencia, por lo que realizaremos una optimización completa del sistema y una actualización de funciones durante el cierre del registro. En el futuro, le daremos la bienvenida con contenido y servicios de mayor calidad.\n\nPor favor, siga nuestro sitio web y plataformas de redes sociales para obtener las últimas actualizaciones y notificaciones. Agradecemos su comprensión y apoyo.\n\nSi tiene alguna pregunta o necesita ayuda, no dude en ponerse en contacto con nuestro equipo de atención al cliente.\n\n**Nuevamente, gracias por su apoyo y comprensión.**",
"passwordMismatch": "Las contraseñas no coinciden", "passwordMismatch": "Las contraseñas no coinciden",
"success": "¡Registro exitoso, has iniciado sesión automáticamente!", "success": "¡Registro exitoso, has iniciado sesión automáticamente!",
+2
View File
@@ -39,6 +39,8 @@
"status": "Estado", "status": "Estado",
"subject": "Asunto", "subject": "Asunto",
"template": "Plantilla", "template": "Plantilla",
"traffic_exceed_email_template": "Plantilla de Notificación de Exceso de Tráfico",
"traffic_exceed_email_templateDescription": "Los marcadores de posición {after}.variable{before} serán reemplazados con datos reales. Asegúrate de mantener estas variables.",
"verify_email_template": "Plantilla de Correo Electrónico de Verificación", "verify_email_template": "Plantilla de Correo Electrónico de Verificación",
"verify_email_templateDescription": "Los marcadores de posición {after}.variable{before} serán reemplazados con datos reales. Asegúrate de mantener estas variables.", "verify_email_templateDescription": "Los marcadores de posición {after}.variable{before} serán reemplazados con datos reales. Asegúrate de mantener estas variables.",
"whitelistSuffixes": "Sufijos de Lista Blanca", "whitelistSuffixes": "Sufijos de Lista Blanca",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "Configuración de ADS", "ADS Config": "Configuración de ADS",
"Announcement Management": "Gestión de Anuncios", "Announcement Management": "Gestión de Anuncios",
"Apple": "ID de Apple", "Apple": "ID de Apple",
"Application Management": "Gestión de Aplicaciones",
"Auth Control": "Control de Autenticación", "Auth Control": "Control de Autenticación",
"Coupon Management": "Gestión de Cupones", "Coupon Management": "Gestión de Cupones",
"Dashboard": "Tablero", "Dashboard": "Tablero",
@@ -16,6 +17,7 @@
"Order Management": "Gestión de Pedidos", "Order Management": "Gestión de Pedidos",
"Payment Config": "Configuración de Pago", "Payment Config": "Configuración de Pago",
"Phone Number": "Número de Teléfono", "Phone Number": "Número de Teléfono",
"Rule Management": "Gestión de Reglas",
"Server": "Servidor", "Server": "Servidor",
"Server Management": "Gestión de Servidores", "Server Management": "Gestión de Servidores",
"Settings": "Configuración", "Settings": "Configuración",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "Analizando...",
"appIcon": "Ícono de Regla",
"cancel": "Cancelar",
"confirm": "Confirmar",
"confirmDelete": "Confirmar Eliminación",
"create": "Agregar Regla",
"createRule": "Agregar Regla",
"createSuccess": "Regla creada con éxito",
"createdAt": "Creado En",
"delete": "Eliminar",
"deleteSuccess": "Regla eliminada con éxito",
"deleteWarning": "¿Está seguro de que desea eliminar esta regla? Esta acción no se puede deshacer.",
"description": "Descripción de la Regla",
"downloadTemplate": "Descargar Plantilla",
"edit": "Editar",
"editRule": "Editar Regla",
"enable": "Habilitar",
"enterIconUrl": "Ingrese o suba un ícono",
"enterRuleName": "Ingrese el nombre de la regla",
"enterRules": "Ingrese el contenido de la regla, uno por línea",
"import": "Importar",
"importFailed": "Importación fallida",
"importSuccess": "Importación exitosa",
"importYaml": "Importar YAML",
"importYamlDescription": "Importar reglas desde un archivo YAML, el sistema creará automáticamente grupos de reglas basados en los nombres de los grupos de políticas",
"importYamlRules": "Importar Reglas YAML",
"importing": "Importando...",
"invalidYamlFormat": "Formato YAML inválido, falta el campo de reglas",
"name": "Nombre de la Regla",
"noValidRules": "No se encontraron reglas válidas",
"pleaseUploadFile": "Por favor, suba un archivo YAML",
"preview": "Vista Previa",
"rules": "Contenido de la Regla",
"rulesFormat": "Formato de regla: tipo de regla, contenido de coincidencia, [política], donde la política es opcional.\nSi no se especifica la política, se utilizará automáticamente el nombre del grupo de reglas actual. Ejemplos:",
"rulesLabel": "Contenido de la Regla",
"searchRule": "Buscar nombre de regla",
"selectFile": "Seleccionar Archivo",
"selectTags": "Seleccionar etiquetas de nodo",
"tags": "Etiquetas de Nodo",
"tagsLabel": "Etiquetas de Nodo",
"updateSuccess": "Regla actualizada con éxito"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "Política de Privacidad" "title": "Política de Privacidad"
}, },
"site": { "site": {
"customData": "Datos Personalizados",
"customDataDescription": "Datos Personalizados, utilizados para datos personalizados del sitio",
"customHtml": "HTML personalizado", "customHtml": "HTML personalizado",
"customHtmlDescription": "Código HTML personalizado que se inyectará al final de la etiqueta body del sitio.", "customHtmlDescription": "Código HTML personalizado que se inyectará al final de la etiqueta body del sitio.",
"keywords": "Palabras clave", "keywords": "Palabras clave",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "Habilitar Cuenta", "accountEnable": "Habilitar Cuenta",
"actions": "acciones", "actions": "acciones",
"active": "Activo",
"add": "Agregar", "add": "Agregar",
"administrator": "Administrador", "administrator": "Administrador",
"areaCode": "Código de Área", "areaCode": "Código de Área",
@@ -41,10 +42,12 @@
"email": "correo electrónico", "email": "correo electrónico",
"enable": "Habilitar", "enable": "Habilitar",
"expireTime": "Tiempo de Expiración", "expireTime": "Tiempo de Expiración",
"expired": "Expirado",
"expiredAt": "Fecha de vencimiento", "expiredAt": "Fecha de vencimiento",
"failed": "Fallido", "failed": "Fallido",
"giftAmount": "Monto del Regalo", "giftAmount": "Monto del Regalo",
"giftAmountPlaceholder": "Ingrese el monto del regalo", "giftAmountPlaceholder": "Ingrese el monto del regalo",
"inactive": "Inactivo",
"invalidEmailFormat": "Formato de correo electrónico no válido", "invalidEmailFormat": "Formato de correo electrónico no válido",
"inviteCode": "Código de Invitación", "inviteCode": "Código de Invitación",
"inviteCodePlaceholder": "Ingresa el código de invitación (déjalo en blanco para generar uno)", "inviteCodePlaceholder": "Ingresa el código de invitación (déjalo en blanco para generar uno)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "Ingresa nueva contraseña (opcional)", "passwordPlaceholder": "Ingresa nueva contraseña (opcional)",
"permanent": "Permanente", "permanent": "Permanente",
"pleaseEnterEmail": "Por favor, ingresa el correo electrónico", "pleaseEnterEmail": "Por favor, ingresa el correo electrónico",
"price": "Precio",
"referer": "Recomendador", "referer": "Recomendador",
"refererId": "ID del Referente", "refererId": "ID del Referente",
"refererIdPlaceholder": "Ingrese ID del referente", "refererIdPlaceholder": "Ingrese ID del referente",
@@ -74,8 +78,12 @@
"searchIp": "Buscar dirección IP", "searchIp": "Buscar dirección IP",
"selectAuthType": "Seleccionar tipo de autenticación", "selectAuthType": "Seleccionar tipo de autenticación",
"speedLimit": "Límite de Velocidad", "speedLimit": "Límite de Velocidad",
"startTime": "Hora de Inicio",
"status": "Estado",
"subscription": "Suscripción", "subscription": "Suscripción",
"subscriptionDetails": "Detalles de la Suscripción", "subscriptionDetails": "Detalles de la Suscripción",
"subscriptionId": "ID de Suscripción",
"subscriptionInfo": "Información de Suscripción",
"subscriptionList": "Lista de Suscripción", "subscriptionList": "Lista de Suscripción",
"subscriptionLogs": "Registros de Suscripción", "subscriptionLogs": "Registros de Suscripción",
"subscriptionName": "Nombre de la Suscripción", "subscriptionName": "Nombre de la Suscripción",
@@ -89,6 +97,8 @@
"tradeNotifications": "Notificaciones de Comercio", "tradeNotifications": "Notificaciones de Comercio",
"trafficLimit": "Límite de Tráfico", "trafficLimit": "Límite de Tráfico",
"trafficLogs": "Registros de Tráfico", "trafficLogs": "Registros de Tráfico",
"trafficUsage": "Uso de Tráfico",
"unknown": "Desconocido",
"unlimited": "Ilimitado", "unlimited": "Ilimitado",
"unverified": "No verificado", "unverified": "No verificado",
"update": "Actualizar", "update": "Actualizar",
@@ -98,11 +108,15 @@
"userAgent": "Agente de Usuario", "userAgent": "Agente de Usuario",
"userEmail": "Correo Electrónico del Usuario", "userEmail": "Correo Electrónico del Usuario",
"userEmailPlaceholder": "Ingresa el correo electrónico del usuario", "userEmailPlaceholder": "Ingresa el correo electrónico del usuario",
"userId": "ID de Usuario",
"userInfo": "Información de Usuario",
"userList": "Lista de usuarios", "userList": "Lista de usuarios",
"userLogs": "Historial de Inicio de Sesión", "userLogs": "Historial de Inicio de Sesión",
"userName": "Identificador de Usuario", "userName": "Identificador de Usuario",
"userOrders": "Pedidos", "userOrders": "Pedidos",
"userProfile": "Perfil", "userProfile": "Perfil",
"userSubscriptions": "Suscripciones", "userSubscriptions": "Suscripciones",
"verified": "Verificado" "username": "Nombre de Usuario",
"verified": "Verificado",
"viewDetails": "Ver Detalles"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "لطفاً یک آدرس ایمیل معتبر وارد کنید.", "email": "لطفاً یک آدرس ایمیل معتبر وارد کنید.",
"existingAccount": "آیا قبلاً حساب کاربری دارید؟", "existingAccount": "آیا قبلاً حساب کاربری دارید؟",
"get": "دریافت", "get": "دریافت",
"invite": "کد دعوت", "invite": "کد دعوت (اختیاری)",
"message": "#### کاربر گرامی، سلام!\n\nاز توجه و حمایت شما سپاسگزاریم. به دلیل تغییرات در استراتژی عملیاتی سایت، عملکرد ثبت‌نام کاربران جدید را متوقف کرده‌ایم. در این مدت، کاربران فعلی تحت تأثیر قرار نخواهند گرفت.\n\nما متعهد به ارائه خدمات و تجربه بهتر به شما هستیم، بنابراین در طول این دوره، بهینه‌سازی جامع سیستم و ارتقاء ویژگی‌ها را انجام خواهیم داد. در آینده، با محتوای و خدمات بهتر از شما استقبال خواهیم کرد.\n\nلطفاً برای دریافت آخرین به‌روزرسانی‌ها و اطلاعیه‌ها، وب‌سایت و پلتفرم‌های اجتماعی ما را دنبال کنید. از درک و حمایت شما سپاسگزاریم.\n\nاگر سوالی دارید یا به کمک نیاز دارید، لطفاً با تیم خدمات مشتری ما تماس بگیرید.\n\n**بار دیگر از حمایت و درک شما سپاسگزاریم.**", "message": "#### کاربر گرامی، سلام!\n\nاز توجه و حمایت شما سپاسگزاریم. به دلیل تغییرات در استراتژی عملیاتی سایت، عملکرد ثبت‌نام کاربران جدید را متوقف کرده‌ایم. در این مدت، کاربران فعلی تحت تأثیر قرار نخواهند گرفت.\n\nما متعهد به ارائه خدمات و تجربه بهتر به شما هستیم، بنابراین در طول این دوره، بهینه‌سازی جامع سیستم و ارتقاء ویژگی‌ها را انجام خواهیم داد. در آینده، با محتوای و خدمات بهتر از شما استقبال خواهیم کرد.\n\nلطفاً برای دریافت آخرین به‌روزرسانی‌ها و اطلاعیه‌ها، وب‌سایت و پلتفرم‌های اجتماعی ما را دنبال کنید. از درک و حمایت شما سپاسگزاریم.\n\nاگر سوالی دارید یا به کمک نیاز دارید، لطفاً با تیم خدمات مشتری ما تماس بگیرید.\n\n**بار دیگر از حمایت و درک شما سپاسگزاریم.**",
"passwordMismatch": "رمزهای عبور مطابقت ندارند", "passwordMismatch": "رمزهای عبور مطابقت ندارند",
"success": "ثبت‌نام موفقیت‌آمیز بود، به‌طور خودکار وارد شدید!", "success": "ثبت‌نام موفقیت‌آمیز بود، به‌طور خودکار وارد شدید!",
+2
View File
@@ -39,6 +39,8 @@
"status": "وضعیت", "status": "وضعیت",
"subject": "موضوع", "subject": "موضوع",
"template": "الگو", "template": "الگو",
"traffic_exceed_email_template": "الگوی اعلان ترافیک بیش از حد",
"traffic_exceed_email_templateDescription": "جایگزین‌های {after}.variable{before} با داده‌های واقعی خواهد شد. اطمینان حاصل کنید که این متغیرها را حفظ کنید.",
"verify_email_template": "قالب ایمیل تأیید", "verify_email_template": "قالب ایمیل تأیید",
"verify_email_templateDescription": "جای‌گذاری‌های {after}.variable{before} با داده‌های واقعی جایگزین خواهند شد. اطمینان حاصل کنید که این متغیرها را حفظ کنید.", "verify_email_templateDescription": "جای‌گذاری‌های {after}.variable{before} با داده‌های واقعی جایگزین خواهند شد. اطمینان حاصل کنید که این متغیرها را حفظ کنید.",
"whitelistSuffixes": "پسوندهای لیست سفید", "whitelistSuffixes": "پسوندهای لیست سفید",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "تنظیمات ADS", "ADS Config": "تنظیمات ADS",
"Announcement Management": "مدیریت اطلاعیه‌ها", "Announcement Management": "مدیریت اطلاعیه‌ها",
"Apple": "شناسه اپل", "Apple": "شناسه اپل",
"Application Management": "مدیریت برنامه",
"Auth Control": "کنترل احراز هویت", "Auth Control": "کنترل احراز هویت",
"Coupon Management": "مدیریت کوپن", "Coupon Management": "مدیریت کوپن",
"Dashboard": "داشبورد", "Dashboard": "داشبورد",
@@ -16,6 +17,7 @@
"Order Management": "مدیریت سفارش", "Order Management": "مدیریت سفارش",
"Payment Config": "پیکربندی پرداخت", "Payment Config": "پیکربندی پرداخت",
"Phone Number": "شماره تلفن", "Phone Number": "شماره تلفن",
"Rule Management": "مدیریت قوانین",
"Server": "سرور", "Server": "سرور",
"Server Management": "مدیریت سرور", "Server Management": "مدیریت سرور",
"Settings": "تنظیمات", "Settings": "تنظیمات",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "در حال تجزیه و تحلیل...",
"appIcon": "آیکون قانون",
"cancel": "لغو",
"confirm": "تأیید",
"confirmDelete": "تأیید حذف",
"create": "افزودن قانون",
"createRule": "افزودن قانون",
"createSuccess": "قانون با موفقیت ایجاد شد",
"createdAt": "تاریخ ایجاد",
"delete": "حذف",
"deleteSuccess": "قانون با موفقیت حذف شد",
"deleteWarning": "آیا مطمئن هستید که می‌خواهید این قانون را حذف کنید؟ این عمل قابل بازگشت نیست.",
"description": "توضیحات قانون",
"downloadTemplate": "دانلود الگو",
"edit": "ویرایش",
"editRule": "ویرایش قانون",
"enable": "فعال‌سازی",
"enterIconUrl": "آدرس یا بارگذاری آیکون را وارد کنید",
"enterRuleName": "نام قانون را وارد کنید",
"enterRules": "محتوای قانون را وارد کنید، هر کدام در یک خط",
"import": "وارد کردن",
"importFailed": "وارد کردن ناموفق بود",
"importSuccess": "وارد کردن با موفقیت انجام شد",
"importYaml": "وارد کردن YAML",
"importYamlDescription": "وارد کردن قوانین از فایل YAML، سیستم به طور خودکار گروه‌های قانونی را بر اساس نام‌های گروه سیاست ایجاد خواهد کرد",
"importYamlRules": "وارد کردن قوانین YAML",
"importing": "در حال وارد کردن...",
"invalidYamlFormat": "فرمت YAML نامعتبر است، فیلد قوانین گم شده است",
"name": "نام قانون",
"noValidRules": "هیچ قانونی یافت نشد",
"pleaseUploadFile": "لطفاً یک فایل YAML بارگذاری کنید",
"preview": "پیش‌نمایش",
"rules": "محتوای قانون",
"rulesFormat": "فرمت قانون: نوع قانون، محتوای تطابق، [سیاست]، که سیاست اختیاری است.\nاگر سیاست مشخص نشود، نام گروه قانونی فعلی به طور خودکار استفاده خواهد شد. مثال‌ها:",
"rulesLabel": "محتوای قانون",
"searchRule": "جستجوی نام قانون",
"selectFile": "انتخاب فایل",
"selectTags": "انتخاب برچسب‌های گره",
"tags": "برچسب‌های گره",
"tagsLabel": "برچسب‌های گره",
"updateSuccess": "قانون با موفقیت به‌روزرسانی شد"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "سیاست حفظ حریم خصوصی" "title": "سیاست حفظ حریم خصوصی"
}, },
"site": { "site": {
"customData": "داده‌های سفارشی",
"customDataDescription": "داده‌های سفارشی، استفاده شده برای داده‌های سفارشی سایت",
"customHtml": "HTML سفارشی", "customHtml": "HTML سفارشی",
"customHtmlDescription": "کد HTML سفارشی که باید در انتهای تگ body سایت وارد شود.", "customHtmlDescription": "کد HTML سفارشی که باید در انتهای تگ body سایت وارد شود.",
"keywords": "کلمات کلیدی", "keywords": "کلمات کلیدی",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "فعال‌سازی حساب", "accountEnable": "فعال‌سازی حساب",
"actions": "اقدامات", "actions": "اقدامات",
"active": "فعال",
"add": "افزودن", "add": "افزودن",
"administrator": "مدیر", "administrator": "مدیر",
"areaCode": "کد منطقه", "areaCode": "کد منطقه",
@@ -41,10 +42,12 @@
"email": "ایمیل", "email": "ایمیل",
"enable": "فعال کردن", "enable": "فعال کردن",
"expireTime": "زمان انقضا", "expireTime": "زمان انقضا",
"expired": "منقضی شده",
"expiredAt": "منقضی شده در", "expiredAt": "منقضی شده در",
"failed": "ناموفق", "failed": "ناموفق",
"giftAmount": "مقدار هدیه", "giftAmount": "مقدار هدیه",
"giftAmountPlaceholder": "مبلغ هدیه را وارد کنید", "giftAmountPlaceholder": "مبلغ هدیه را وارد کنید",
"inactive": "غیرفعال",
"invalidEmailFormat": "فرمت ایمیل نامعتبر است", "invalidEmailFormat": "فرمت ایمیل نامعتبر است",
"inviteCode": "کد دعوت", "inviteCode": "کد دعوت",
"inviteCodePlaceholder": "کد دعوت را وارد کنید (برای تولید خالی بگذارید)", "inviteCodePlaceholder": "کد دعوت را وارد کنید (برای تولید خالی بگذارید)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "رمز عبور جدید را وارد کنید (اختیاری)", "passwordPlaceholder": "رمز عبور جدید را وارد کنید (اختیاری)",
"permanent": "دائمی", "permanent": "دائمی",
"pleaseEnterEmail": "لطفاً ایمیل خود را وارد کنید", "pleaseEnterEmail": "لطفاً ایمیل خود را وارد کنید",
"price": "قیمت",
"referer": "ارجاع‌دهنده", "referer": "ارجاع‌دهنده",
"refererId": "شناسه معرف", "refererId": "شناسه معرف",
"refererIdPlaceholder": "شناسه معرف را وارد کنید", "refererIdPlaceholder": "شناسه معرف را وارد کنید",
@@ -74,8 +78,12 @@
"searchIp": "جستجوی آدرس IP", "searchIp": "جستجوی آدرس IP",
"selectAuthType": "نوع احراز هویت را انتخاب کنید", "selectAuthType": "نوع احراز هویت را انتخاب کنید",
"speedLimit": "محدودیت سرعت", "speedLimit": "محدودیت سرعت",
"startTime": "زمان شروع",
"status": "وضعیت",
"subscription": "اشتراک", "subscription": "اشتراک",
"subscriptionDetails": "جزئیات اشتراک", "subscriptionDetails": "جزئیات اشتراک",
"subscriptionId": "شناسه اشتراک",
"subscriptionInfo": "اطلاعات اشتراک",
"subscriptionList": "لیست اشتراک", "subscriptionList": "لیست اشتراک",
"subscriptionLogs": "گزارش‌های اشتراک", "subscriptionLogs": "گزارش‌های اشتراک",
"subscriptionName": "نام اشتراک", "subscriptionName": "نام اشتراک",
@@ -89,6 +97,8 @@
"tradeNotifications": "اعلان‌های تجارت", "tradeNotifications": "اعلان‌های تجارت",
"trafficLimit": "محدودیت ترافیک", "trafficLimit": "محدودیت ترافیک",
"trafficLogs": "گزارش‌های ترافیک", "trafficLogs": "گزارش‌های ترافیک",
"trafficUsage": "استفاده از ترافیک",
"unknown": "نامشخص",
"unlimited": "نامحدود", "unlimited": "نامحدود",
"unverified": "تأیید نشده", "unverified": "تأیید نشده",
"update": "به‌روزرسانی", "update": "به‌روزرسانی",
@@ -98,11 +108,15 @@
"userAgent": "عامل کاربر", "userAgent": "عامل کاربر",
"userEmail": "ایمیل کاربر", "userEmail": "ایمیل کاربر",
"userEmailPlaceholder": "ایمیل کاربر را وارد کنید", "userEmailPlaceholder": "ایمیل کاربر را وارد کنید",
"userId": "شناسه کاربر",
"userInfo": "اطلاعات کاربر",
"userList": "فهرست کاربران", "userList": "فهرست کاربران",
"userLogs": "تاریخچه ورود", "userLogs": "تاریخچه ورود",
"userName": "شناسه کاربر", "userName": "شناسه کاربر",
"userOrders": "سفارش‌ها", "userOrders": "سفارش‌ها",
"userProfile": "پروفایل", "userProfile": "پروفایل",
"userSubscriptions": "اشتراک‌ها", "userSubscriptions": "اشتراک‌ها",
"verified": "تأیید شده" "username": "نام کاربری",
"verified": "تأیید شده",
"viewDetails": "مشاهده جزئیات"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "Anna kelvollinen sähköpostiosoite.", "email": "Anna kelvollinen sähköpostiosoite.",
"existingAccount": "Onko sinulla jo tili?", "existingAccount": "Onko sinulla jo tili?",
"get": "Hanki", "get": "Hanki",
"invite": "Kutsukoodi", "invite": "Kutsukoodi (valinnainen)",
"message": "#### Arvoisa käyttäjä,\n\nKiitos mielenkiinnostasi ja tuestasi. Sivuston toimintastrategian muutosten vuoksi olemme sulkeneet uusien käyttäjien rekisteröinnin. Tänä aikana nykyisten käyttäjien käyttö ei vaikutu millään tavalla.\n\nOlemme sitoutuneet tarjoamaan sinulle parempaa palvelua ja kokemusta, joten rekisteröinnin sulkemisen aikana suoritamme kattavan järjestelmän optimoinnin ja toiminnallisuuden päivityksen. Tulevaisuudessa toivotamme sinut tervetulleeksi entistä laadukkaamman sisällön ja palvelun kera.\n\nSeuraa verkkosivustoamme ja sosiaalisen median alustoja saadaksesi uusimmat päivitykset ja ilmoitukset. Kiitos ymmärryksestäsi ja tuestasi.\n\nJos sinulla on kysyttävää tai tarvitset apua, ota yhteyttä asiakaspalvelutiimiimme.\n\n**Kiitos vielä kerran tuestasi ja ymmärryksestäsi.**", "message": "#### Arvoisa käyttäjä,\n\nKiitos mielenkiinnostasi ja tuestasi. Sivuston toimintastrategian muutosten vuoksi olemme sulkeneet uusien käyttäjien rekisteröinnin. Tänä aikana nykyisten käyttäjien käyttö ei vaikutu millään tavalla.\n\nOlemme sitoutuneet tarjoamaan sinulle parempaa palvelua ja kokemusta, joten rekisteröinnin sulkemisen aikana suoritamme kattavan järjestelmän optimoinnin ja toiminnallisuuden päivityksen. Tulevaisuudessa toivotamme sinut tervetulleeksi entistä laadukkaamman sisällön ja palvelun kera.\n\nSeuraa verkkosivustoamme ja sosiaalisen median alustoja saadaksesi uusimmat päivitykset ja ilmoitukset. Kiitos ymmärryksestäsi ja tuestasi.\n\nJos sinulla on kysyttävää tai tarvitset apua, ota yhteyttä asiakaspalvelutiimiimme.\n\n**Kiitos vielä kerran tuestasi ja ymmärryksestäsi.**",
"passwordMismatch": "Salasanat eivät täsmää", "passwordMismatch": "Salasanat eivät täsmää",
"success": "Rekisteröinti onnistui, olet kirjautunut automaattisesti!", "success": "Rekisteröinti onnistui, olet kirjautunut automaattisesti!",
+2
View File
@@ -39,6 +39,8 @@
"status": "Tila", "status": "Tila",
"subject": "Aihe", "subject": "Aihe",
"template": "Malline", "template": "Malline",
"traffic_exceed_email_template": "Liikenteen Ylitysilmoitusmalli",
"traffic_exceed_email_templateDescription": "{after}.variable{before} -paikat korvataan todellisilla tiedoilla. Varmista, että säilytät nämä muuttujat.",
"verify_email_template": "Sähköpostin Vahvistusmalli", "verify_email_template": "Sähköpostin Vahvistusmalli",
"verify_email_templateDescription": "Paikkamerkit {after}.variable{before} korvataan todellisilla tiedoilla. Varmista, että pidät nämä muuttujat.", "verify_email_templateDescription": "Paikkamerkit {after}.variable{before} korvataan todellisilla tiedoilla. Varmista, että pidät nämä muuttujat.",
"whitelistSuffixes": "Sallittujen luetteloiden päätteet", "whitelistSuffixes": "Sallittujen luetteloiden päätteet",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "ADS-asetukset", "ADS Config": "ADS-asetukset",
"Announcement Management": "Ilmoitusten hallinta", "Announcement Management": "Ilmoitusten hallinta",
"Apple": "Apple ID", "Apple": "Apple ID",
"Application Management": "Sovellushallinta",
"Auth Control": "Todennuksen hallinta", "Auth Control": "Todennuksen hallinta",
"Coupon Management": "Kuponkien hallinta", "Coupon Management": "Kuponkien hallinta",
"Dashboard": "Kojelauta", "Dashboard": "Kojelauta",
@@ -16,6 +17,7 @@
"Order Management": "Tilausten hallinta", "Order Management": "Tilausten hallinta",
"Payment Config": "Maksukonfiguraatio", "Payment Config": "Maksukonfiguraatio",
"Phone Number": "Puhelinnumero", "Phone Number": "Puhelinnumero",
"Rule Management": "Sääntöhallinta",
"Server": "Palvelu", "Server": "Palvelu",
"Server Management": "Palvelimen hallinta", "Server Management": "Palvelimen hallinta",
"Settings": "Asetukset", "Settings": "Asetukset",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "Analysoidaan...",
"appIcon": "Sääntökuvake",
"cancel": "Peruuta",
"confirm": "Vahvista",
"confirmDelete": "Vahvista poisto",
"create": "Lisää sääntö",
"createRule": "Lisää sääntö",
"createSuccess": "Sääntö luotiin onnistuneesti",
"createdAt": "Luotu",
"delete": "Poista",
"deleteSuccess": "Sääntö poistettiin onnistuneesti",
"deleteWarning": "Oletko varma, että haluat poistaa tämän säännön? Tätä toimintoa ei voi peruuttaa.",
"description": "Säännön kuvaus",
"downloadTemplate": "Lataa malli",
"edit": "Muokkaa",
"editRule": "Muokkaa sääntöä",
"enable": "Ota käyttöön",
"enterIconUrl": "Syötä tai lataa kuvake",
"enterRuleName": "Syötä säännön nimi",
"enterRules": "Syötä sääntöjen sisältö, yksi per rivi",
"import": "Tuoda",
"importFailed": "Tuonti epäonnistui",
"importSuccess": "Tuonti onnistui",
"importYaml": "Tuo YAML",
"importYamlDescription": "Tuo sääntöjä YAML-tiedostosta, järjestelmä luo automaattisesti sääntöryhmiä politiikkaryhmän nimien perusteella",
"importYamlRules": "Tuo YAML-säännöt",
"importing": "Tuodaan...",
"invalidYamlFormat": "Virheellinen YAML-muoto, puuttuu sääntöjen kenttä",
"name": "Säännön nimi",
"noValidRules": "Ei voimassa olevia sääntöjä löytynyt",
"pleaseUploadFile": "Lataa YAML-tiedosto",
"preview": "Esikatselu",
"rules": "Säännön sisältö",
"rulesFormat": "Sääntömuoto: sääntötyyppi, vastaavuus, [politiikka], jossa politiikka on valinnainen.\nJos politiikkaa ei ole määritelty, nykyistä sääntöryhmän nimeä käytetään automaattisesti. Esimerkkejä:",
"rulesLabel": "Säännön sisältö",
"searchRule": "Etsi säännön nimeä",
"selectFile": "Valitse tiedosto",
"selectTags": "Valitse solmun tunnisteet",
"tags": "Solmun tunnisteet",
"tagsLabel": "Solmun tunnisteet",
"updateSuccess": "Sääntö päivitettiin onnistuneesti"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "Tietosuojakäytäntö" "title": "Tietosuojakäytäntö"
}, },
"site": { "site": {
"customData": "Mukautettu tieto",
"customDataDescription": "Mukautettu tieto, jota käytetään sivuston mukautettuun tietoon",
"customHtml": "Mukautettu HTML", "customHtml": "Mukautettu HTML",
"customHtmlDescription": "Mukautettu HTML-koodi, joka lisätään sivuston body -tagin loppuun.", "customHtmlDescription": "Mukautettu HTML-koodi, joka lisätään sivuston body -tagin loppuun.",
"keywords": "Avainsanat", "keywords": "Avainsanat",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "Tilin aktivointi", "accountEnable": "Tilin aktivointi",
"actions": "toiminnot", "actions": "toiminnot",
"active": "Aktiivinen",
"add": "Lisää", "add": "Lisää",
"administrator": "Ylläpitäjä", "administrator": "Ylläpitäjä",
"areaCode": "Alueen koodi", "areaCode": "Alueen koodi",
@@ -41,10 +42,12 @@
"email": "sähköposti", "email": "sähköposti",
"enable": "Ota käyttöön", "enable": "Ota käyttöön",
"expireTime": "Vanhentumisaika", "expireTime": "Vanhentumisaika",
"expired": "Vanhentunut",
"expiredAt": "Vanhentunut", "expiredAt": "Vanhentunut",
"failed": "Epäonnistui", "failed": "Epäonnistui",
"giftAmount": "Lahjan määrä", "giftAmount": "Lahjan määrä",
"giftAmountPlaceholder": "Syötä lahjan määrä", "giftAmountPlaceholder": "Syötä lahjan määrä",
"inactive": "Epäaktiivinen",
"invalidEmailFormat": "Virheellinen sähköpostimuoto", "invalidEmailFormat": "Virheellinen sähköpostimuoto",
"inviteCode": "Kutsukoodi", "inviteCode": "Kutsukoodi",
"inviteCodePlaceholder": "Syötä kutsukoodi (jätä tyhjäksi luodaksesi uuden)", "inviteCodePlaceholder": "Syötä kutsukoodi (jätä tyhjäksi luodaksesi uuden)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "Syötä uusi salasana (valinnainen)", "passwordPlaceholder": "Syötä uusi salasana (valinnainen)",
"permanent": "Pysyvä", "permanent": "Pysyvä",
"pleaseEnterEmail": "Ole hyvä ja syötä sähköpostiosoite", "pleaseEnterEmail": "Ole hyvä ja syötä sähköpostiosoite",
"price": "Hinta",
"referer": "Suosittelija", "referer": "Suosittelija",
"refererId": "Viittaajan ID", "refererId": "Viittaajan ID",
"refererIdPlaceholder": "Syötä suosittelijan ID", "refererIdPlaceholder": "Syötä suosittelijan ID",
@@ -74,8 +78,12 @@
"searchIp": "Etsi IP-osoite", "searchIp": "Etsi IP-osoite",
"selectAuthType": "Valitse todennustyyppi", "selectAuthType": "Valitse todennustyyppi",
"speedLimit": "Nopeusrajoitus", "speedLimit": "Nopeusrajoitus",
"startTime": "Aloitusaika",
"status": "Tila",
"subscription": "Tilaus", "subscription": "Tilaus",
"subscriptionDetails": "Tilaustiedot", "subscriptionDetails": "Tilaustiedot",
"subscriptionId": "Tilauksen ID",
"subscriptionInfo": "Tilauksen tiedot",
"subscriptionList": "Tilauksen lista", "subscriptionList": "Tilauksen lista",
"subscriptionLogs": "Tilaushistoria", "subscriptionLogs": "Tilaushistoria",
"subscriptionName": "Tilauksen nimi", "subscriptionName": "Tilauksen nimi",
@@ -89,6 +97,8 @@
"tradeNotifications": "Kauppailmoitukset", "tradeNotifications": "Kauppailmoitukset",
"trafficLimit": "Liikenteen rajoitus", "trafficLimit": "Liikenteen rajoitus",
"trafficLogs": "Liikennelokit", "trafficLogs": "Liikennelokit",
"trafficUsage": "Liikenteen käyttö",
"unknown": "Tuntematon",
"unlimited": "Rajoittamaton", "unlimited": "Rajoittamaton",
"unverified": "Vahvistamaton", "unverified": "Vahvistamaton",
"update": "Päivitä", "update": "Päivitä",
@@ -98,11 +108,15 @@
"userAgent": "Käyttäjäagentti", "userAgent": "Käyttäjäagentti",
"userEmail": "Käyttäjän sähköposti", "userEmail": "Käyttäjän sähköposti",
"userEmailPlaceholder": "Syötä käyttäjän sähköpostiosoite", "userEmailPlaceholder": "Syötä käyttäjän sähköpostiosoite",
"userId": "Käyttäjän ID",
"userInfo": "Käyttäjän tiedot",
"userList": "Käyttäjälista", "userList": "Käyttäjälista",
"userLogs": "Kirjautumishistoria", "userLogs": "Kirjautumishistoria",
"userName": "Käyttäjän tunniste", "userName": "Käyttäjän tunniste",
"userOrders": "Tilaukset", "userOrders": "Tilaukset",
"userProfile": "Profiili", "userProfile": "Profiili",
"userSubscriptions": "Tilaukset", "userSubscriptions": "Tilaukset",
"verified": "Vahvistettu" "username": "Käyttäjänimi",
"verified": "Vahvistettu",
"viewDetails": "Näytä tiedot"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "Veuillez entrer une adresse e-mail valide.", "email": "Veuillez entrer une adresse e-mail valide.",
"existingAccount": "Vous avez déjà un compte ?", "existingAccount": "Vous avez déjà un compte ?",
"get": "Obtenir", "get": "Obtenir",
"invite": "Code d'invitation", "invite": "Code d'invitation (facultatif)",
"message": "#### Cher utilisateur,\n\nMerci pour votre intérêt et votre soutien. En raison d'un ajustement de notre stratégie opérationnelle, nous avons fermé la fonction d'inscription pour les nouveaux utilisateurs. Pendant cette période, l'utilisation par les utilisateurs existants ne sera pas affectée.\n\nNous nous engageons à vous offrir un meilleur service et une meilleure expérience, c'est pourquoi nous procéderons à une optimisation complète du système et à une mise à niveau des fonctionnalités pendant la fermeture des inscriptions. À l'avenir, nous vous accueillerons avec un contenu et des services de meilleure qualité.\n\nVeuillez suivre notre site web et nos plateformes de médias sociaux pour obtenir les dernières nouvelles et notifications. Merci pour votre compréhension et votre soutien.\n\nSi vous avez des questions ou avez besoin d'aide, n'hésitez pas à contacter notre équipe de service client.\n\n**Merci encore pour votre soutien et votre compréhension.**", "message": "#### Cher utilisateur,\n\nMerci pour votre intérêt et votre soutien. En raison d'un ajustement de notre stratégie opérationnelle, nous avons fermé la fonction d'inscription pour les nouveaux utilisateurs. Pendant cette période, l'utilisation par les utilisateurs existants ne sera pas affectée.\n\nNous nous engageons à vous offrir un meilleur service et une meilleure expérience, c'est pourquoi nous procéderons à une optimisation complète du système et à une mise à niveau des fonctionnalités pendant la fermeture des inscriptions. À l'avenir, nous vous accueillerons avec un contenu et des services de meilleure qualité.\n\nVeuillez suivre notre site web et nos plateformes de médias sociaux pour obtenir les dernières nouvelles et notifications. Merci pour votre compréhension et votre soutien.\n\nSi vous avez des questions ou avez besoin d'aide, n'hésitez pas à contacter notre équipe de service client.\n\n**Merci encore pour votre soutien et votre compréhension.**",
"passwordMismatch": "Les mots de passe saisis ne correspondent pas", "passwordMismatch": "Les mots de passe saisis ne correspondent pas",
"success": "Inscription réussie, vous êtes maintenant connecté automatiquement !", "success": "Inscription réussie, vous êtes maintenant connecté automatiquement !",
+2
View File
@@ -39,6 +39,8 @@
"status": "Statut", "status": "Statut",
"subject": "Sujet", "subject": "Sujet",
"template": "Modèle", "template": "Modèle",
"traffic_exceed_email_template": "Modèle de notification de dépassement de trafic",
"traffic_exceed_email_templateDescription": "Les espaces réservés {after}.variable{before} seront remplacés par des données réelles. Assurez-vous de conserver ces variables.",
"verify_email_template": "Modèle d'Email de Vérification", "verify_email_template": "Modèle d'Email de Vérification",
"verify_email_templateDescription": "Les espaces réservés {after}.variable{before} seront remplacés par des données réelles. Assurez-vous de conserver ces variables.", "verify_email_templateDescription": "Les espaces réservés {after}.variable{before} seront remplacés par des données réelles. Assurez-vous de conserver ces variables.",
"whitelistSuffixes": "Suffixes de la liste blanche", "whitelistSuffixes": "Suffixes de la liste blanche",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "Configuration ADS", "ADS Config": "Configuration ADS",
"Announcement Management": "Gestion des annonces", "Announcement Management": "Gestion des annonces",
"Apple": "Identifiant Apple", "Apple": "Identifiant Apple",
"Application Management": "Gestion des applications",
"Auth Control": "Contrôle d'authentification", "Auth Control": "Contrôle d'authentification",
"Coupon Management": "Gestion des coupons", "Coupon Management": "Gestion des coupons",
"Dashboard": "Tableau de bord", "Dashboard": "Tableau de bord",
@@ -16,6 +17,7 @@
"Order Management": "Gestion des commandes", "Order Management": "Gestion des commandes",
"Payment Config": "Configuration de paiement", "Payment Config": "Configuration de paiement",
"Phone Number": "Numéro de téléphone", "Phone Number": "Numéro de téléphone",
"Rule Management": "Gestion des règles",
"Server": "Serveur", "Server": "Serveur",
"Server Management": "Gestion des services", "Server Management": "Gestion des services",
"Settings": "Paramètres", "Settings": "Paramètres",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "Analyse en cours...",
"appIcon": "Icône de règle",
"cancel": "Annuler",
"confirm": "Confirmer",
"confirmDelete": "Confirmer la suppression",
"create": "Ajouter une règle",
"createRule": "Ajouter une règle",
"createSuccess": "Règle créée avec succès",
"createdAt": "Créé le",
"delete": "Supprimer",
"deleteSuccess": "Règle supprimée avec succès",
"deleteWarning": "Êtes-vous sûr de vouloir supprimer cette règle ? Cette action ne peut pas être annulée.",
"description": "Description de la règle",
"downloadTemplate": "Télécharger le modèle",
"edit": "Modifier",
"editRule": "Modifier la règle",
"enable": "Activer",
"enterIconUrl": "Entrez ou téléchargez une icône",
"enterRuleName": "Entrez le nom de la règle",
"enterRules": "Entrez le contenu de la règle, un par ligne",
"import": "Importer",
"importFailed": "Échec de l'importation",
"importSuccess": "Importation réussie",
"importYaml": "Importer YAML",
"importYamlDescription": "Importer des règles à partir d'un fichier YAML, le système créera automatiquement des groupes de règles en fonction des noms de groupes de politiques",
"importYamlRules": "Importer des règles YAML",
"importing": "Importation en cours...",
"invalidYamlFormat": "Format YAML invalide, champ de règles manquant",
"name": "Nom de la règle",
"noValidRules": "Aucune règle valide trouvée",
"pleaseUploadFile": "Veuillez télécharger un fichier YAML",
"preview": "Aperçu",
"rules": "Contenu de la règle",
"rulesFormat": "Format de la règle : type de règle, contenu de correspondance, [politique], où la politique est optionnelle.\nSi la politique n'est pas spécifiée, le nom du groupe de règles actuel sera utilisé automatiquement. Exemples :",
"rulesLabel": "Contenu de la règle",
"searchRule": "Rechercher le nom de la règle",
"selectFile": "Sélectionner un fichier",
"selectTags": "Sélectionner des balises de nœud",
"tags": "Balises de nœud",
"tagsLabel": "Balises de nœud",
"updateSuccess": "Règle mise à jour avec succès"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "Politique de confidentialité" "title": "Politique de confidentialité"
}, },
"site": { "site": {
"customData": "Données personnalisées",
"customDataDescription": "Données personnalisées, utilisées pour les données personnalisées du site",
"customHtml": "HTML personnalisé", "customHtml": "HTML personnalisé",
"customHtmlDescription": "Code HTML personnalisé à injecter dans le bas de la balise body du site.", "customHtmlDescription": "Code HTML personnalisé à injecter dans le bas de la balise body du site.",
"keywords": "Mots-clés", "keywords": "Mots-clés",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "Activation du compte", "accountEnable": "Activation du compte",
"actions": "actions", "actions": "actions",
"active": "Actif",
"add": "Ajouter", "add": "Ajouter",
"administrator": "Administrateur", "administrator": "Administrateur",
"areaCode": "Indicatif régional", "areaCode": "Indicatif régional",
@@ -41,10 +42,12 @@
"email": "e-mail", "email": "e-mail",
"enable": "Activer", "enable": "Activer",
"expireTime": "Date d'expiration", "expireTime": "Date d'expiration",
"expired": "Expiré",
"expiredAt": "Expiré le", "expiredAt": "Expiré le",
"failed": "Échoué", "failed": "Échoué",
"giftAmount": "Montant du cadeau", "giftAmount": "Montant du cadeau",
"giftAmountPlaceholder": "Entrez le montant du cadeau", "giftAmountPlaceholder": "Entrez le montant du cadeau",
"inactive": "Inactif",
"invalidEmailFormat": "Format d'email invalide", "invalidEmailFormat": "Format d'email invalide",
"inviteCode": "Code d'invitation", "inviteCode": "Code d'invitation",
"inviteCodePlaceholder": "Entrez le code d'invitation (laissez vide pour générer)", "inviteCodePlaceholder": "Entrez le code d'invitation (laissez vide pour générer)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "Entrez un nouveau mot de passe (facultatif)", "passwordPlaceholder": "Entrez un nouveau mot de passe (facultatif)",
"permanent": "Permanent", "permanent": "Permanent",
"pleaseEnterEmail": "Veuillez entrer votre adresse e-mail", "pleaseEnterEmail": "Veuillez entrer votre adresse e-mail",
"price": "Prix",
"referer": "Référent", "referer": "Référent",
"refererId": "ID du référent", "refererId": "ID du référent",
"refererIdPlaceholder": "Entrez l'ID du référent", "refererIdPlaceholder": "Entrez l'ID du référent",
@@ -74,8 +78,12 @@
"searchIp": "Rechercher une adresse IP", "searchIp": "Rechercher une adresse IP",
"selectAuthType": "Sélectionner le type d'authentification", "selectAuthType": "Sélectionner le type d'authentification",
"speedLimit": "Limite de vitesse", "speedLimit": "Limite de vitesse",
"startTime": "Date de début",
"status": "Statut",
"subscription": "Abonnement", "subscription": "Abonnement",
"subscriptionDetails": "Détails de l'abonnement", "subscriptionDetails": "Détails de l'abonnement",
"subscriptionId": "ID d'abonnement",
"subscriptionInfo": "Informations sur l'abonnement",
"subscriptionList": "Liste des abonnements", "subscriptionList": "Liste des abonnements",
"subscriptionLogs": "Journaux d'abonnement", "subscriptionLogs": "Journaux d'abonnement",
"subscriptionName": "Nom de l'abonnement", "subscriptionName": "Nom de l'abonnement",
@@ -89,6 +97,8 @@
"tradeNotifications": "Notifications de commerce", "tradeNotifications": "Notifications de commerce",
"trafficLimit": "Limite de trafic", "trafficLimit": "Limite de trafic",
"trafficLogs": "Journaux de trafic", "trafficLogs": "Journaux de trafic",
"trafficUsage": "Utilisation du trafic",
"unknown": "Inconnu",
"unlimited": "Illimité", "unlimited": "Illimité",
"unverified": "Non vérifié", "unverified": "Non vérifié",
"update": "Mettre à jour", "update": "Mettre à jour",
@@ -98,11 +108,15 @@
"userAgent": "Agent utilisateur", "userAgent": "Agent utilisateur",
"userEmail": "E-mail de l'utilisateur", "userEmail": "E-mail de l'utilisateur",
"userEmailPlaceholder": "Entrez l'email de l'utilisateur", "userEmailPlaceholder": "Entrez l'email de l'utilisateur",
"userId": "ID utilisateur",
"userInfo": "Informations sur l'utilisateur",
"userList": "Liste des utilisateurs", "userList": "Liste des utilisateurs",
"userLogs": "Historique des connexions", "userLogs": "Historique des connexions",
"userName": "Identifiant Utilisateur", "userName": "Identifiant Utilisateur",
"userOrders": "Commandes", "userOrders": "Commandes",
"userProfile": "Profil", "userProfile": "Profil",
"userSubscriptions": "Abonnements", "userSubscriptions": "Abonnements",
"verified": "Vérifié" "username": "Nom d'utilisateur",
"verified": "Vérifié",
"viewDetails": "Voir les détails"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "कृपया एक मान्य ईमेल पता दर्ज करें।", "email": "कृपया एक मान्य ईमेल पता दर्ज करें।",
"existingAccount": "पहले से खाता है?", "existingAccount": "पहले से खाता है?",
"get": "प्राप्त करें", "get": "प्राप्त करें",
"invite": "आमंत्रण कोड", "invite": "आमंत्रण कोड (वैकल्पिक)",
"message": "#### प्रिय उपयोगकर्ता, नमस्ते!\n\nहमारे प्रति आपकी रुचि और समर्थन के लिए धन्यवाद। साइट संचालन रणनीति में बदलाव के कारण, हमने नए उपयोगकर्ता पंजीकरण को बंद कर दिया है। इस दौरान, मौजूदा उपयोगकर्ताओं के उपयोग पर कोई प्रभाव नहीं पड़ेगा।\n\nहम आपको बेहतर सेवा और अनुभव प्रदान करने के लिए प्रतिबद्ध हैं, इसलिए पंजीकरण बंद होने के दौरान हम व्यापक प्रणाली अनुकूलन और कार्यक्षमता उन्नयन करेंगे। भविष्य में, हम आपको बेहतर सामग्री और सेवाओं के साथ स्वागत करेंगे।\n\nहमारी वेबसाइट और सोशल मीडिया प्लेटफॉर्म पर नवीनतम अपडेट और सूचनाएं प्राप्त करने के लिए ध्यान दें। आपकी समझ और समर्थन के लिए धन्यवाद।\n\nयदि आपके कोई प्रश्न हैं या सहायता की आवश्यकता है, तो कृपया हमारी ग्राहक सेवा टीम से संपर्क करें।\n\n**आपके समर्थन और समझ के लिए एक बार फिर धन्यवाद।**", "message": "#### प्रिय उपयोगकर्ता, नमस्ते!\n\nहमारे प्रति आपकी रुचि और समर्थन के लिए धन्यवाद। साइट संचालन रणनीति में बदलाव के कारण, हमने नए उपयोगकर्ता पंजीकरण को बंद कर दिया है। इस दौरान, मौजूदा उपयोगकर्ताओं के उपयोग पर कोई प्रभाव नहीं पड़ेगा।\n\nहम आपको बेहतर सेवा और अनुभव प्रदान करने के लिए प्रतिबद्ध हैं, इसलिए पंजीकरण बंद होने के दौरान हम व्यापक प्रणाली अनुकूलन और कार्यक्षमता उन्नयन करेंगे। भविष्य में, हम आपको बेहतर सामग्री और सेवाओं के साथ स्वागत करेंगे।\n\nहमारी वेबसाइट और सोशल मीडिया प्लेटफॉर्म पर नवीनतम अपडेट और सूचनाएं प्राप्त करने के लिए ध्यान दें। आपकी समझ और समर्थन के लिए धन्यवाद।\n\nयदि आपके कोई प्रश्न हैं या सहायता की आवश्यकता है, तो कृपया हमारी ग्राहक सेवा टीम से संपर्क करें।\n\n**आपके समर्थन और समझ के लिए एक बार फिर धन्यवाद।**",
"passwordMismatch": "दोनों बार दर्ज किया गया पासवर्ड मेल नहीं खा रहा है", "passwordMismatch": "दोनों बार दर्ज किया गया पासवर्ड मेल नहीं खा रहा है",
"success": "पंजीकरण सफल, स्वचालित रूप से लॉग इन हो गया!", "success": "पंजीकरण सफल, स्वचालित रूप से लॉग इन हो गया!",
+2
View File
@@ -39,6 +39,8 @@
"status": "स्थिति", "status": "स्थिति",
"subject": "विषय", "subject": "विषय",
"template": "टेम्पलेट", "template": "टेम्पलेट",
"traffic_exceed_email_template": "ट्रैफिक अधिकता सूचना टेम्पलेट",
"traffic_exceed_email_templateDescription": "{after}.variable{before} प्लेसहोल्डर्स को वास्तविक डेटा के साथ प्रतिस्थापित किया जाएगा। सुनिश्चित करें कि इन वेरिएबल्स को बनाए रखें।",
"verify_email_template": "सत्यापन ईमेल टेम्पलेट", "verify_email_template": "सत्यापन ईमेल टेम्पलेट",
"verify_email_templateDescription": "{after}.variable{before} प्लेसहोल्डर्स को वास्तविक डेटा से बदला जाएगा। सुनिश्चित करें कि इन वेरिएबल्स को बनाए रखें।", "verify_email_templateDescription": "{after}.variable{before} प्लेसहोल्डर्स को वास्तविक डेटा से बदला जाएगा। सुनिश्चित करें कि इन वेरिएबल्स को बनाए रखें।",
"whitelistSuffixes": "श्वेतसूची प्रत्यय", "whitelistSuffixes": "श्वेतसूची प्रत्यय",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "एडीएस कॉन्फ़िग", "ADS Config": "एडीएस कॉन्फ़िग",
"Announcement Management": "घोषणा प्रबंधन", "Announcement Management": "घोषणा प्रबंधन",
"Apple": "एप्पल आईडी", "Apple": "एप्पल आईडी",
"Application Management": "ऐप्लिकेशन प्रबंधन",
"Auth Control": "प्रमाणिकरण नियंत्रण", "Auth Control": "प्रमाणिकरण नियंत्रण",
"Coupon Management": "कूपन प्रबंधन", "Coupon Management": "कूपन प्रबंधन",
"Dashboard": "डैशबोर्ड", "Dashboard": "डैशबोर्ड",
@@ -16,6 +17,7 @@
"Order Management": "ऑर्डर प्रबंधन", "Order Management": "ऑर्डर प्रबंधन",
"Payment Config": "भुगतान कॉन्फ़िगरेशन", "Payment Config": "भुगतान कॉन्फ़िगरेशन",
"Phone Number": "फ़ोन नंबर", "Phone Number": "फ़ोन नंबर",
"Rule Management": "नियम प्रबंधन",
"Server": "सर्वर", "Server": "सर्वर",
"Server Management": "सर्वर प्रबंधन", "Server Management": "सर्वर प्रबंधन",
"Settings": "सेटिंग्स", "Settings": "सेटिंग्स",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "विश्लेषण कर रहा है...",
"appIcon": "नियम आइकन",
"cancel": "रद्द करें",
"confirm": "पुष्टि करें",
"confirmDelete": "हटाने की पुष्टि करें",
"create": "नियम जोड़ें",
"createRule": "नियम जोड़ें",
"createSuccess": "नियम सफलतापूर्वक बनाया गया",
"createdAt": "बनाया गया",
"delete": "हटाएं",
"deleteSuccess": "नियम सफलतापूर्वक हटाया गया",
"deleteWarning": "क्या आप वाकई इस नियम को हटाना चाहते हैं? यह क्रिया पूर्ववत नहीं की जा सकती।",
"description": "नियम विवरण",
"downloadTemplate": "टेम्पलेट डाउनलोड करें",
"edit": "संपादित करें",
"editRule": "नियम संपादित करें",
"enable": "सक्षम करें",
"enterIconUrl": "एक आइकन दर्ज करें या अपलोड करें",
"enterRuleName": "नियम का नाम दर्ज करें",
"enterRules": "नियम की सामग्री दर्ज करें, एक प्रति पंक्ति",
"import": "आयात करें",
"importFailed": "आयात विफल",
"importSuccess": "आयात सफल",
"importYaml": "YAML आयात करें",
"importYamlDescription": "YAML फ़ाइल से नियम आयात करें, प्रणाली स्वचालित रूप से नीति समूह नामों के आधार पर नियम समूह बनाएगी",
"importYamlRules": "YAML नियम आयात करें",
"importing": "आयात कर रहा है...",
"invalidYamlFormat": "अमान्य YAML प्रारूप, नियम फ़ील्ड गायब है",
"name": "नियम का नाम",
"noValidRules": "कोई मान्य नियम नहीं मिला",
"pleaseUploadFile": "कृपया एक YAML फ़ाइल अपलोड करें",
"preview": "पूर्वावलोकन",
"rules": "नियम सामग्री",
"rulesFormat": "नियम प्रारूप: नियम प्रकार, मिलान सामग्री, [नीति], जहाँ नीति वैकल्पिक है।\nयदि नीति निर्दिष्ट नहीं की गई है, तो वर्तमान नियम समूह का नाम स्वचालित रूप से उपयोग किया जाएगा। उदाहरण:",
"rulesLabel": "नियम सामग्री",
"searchRule": "नियम नाम खोजें",
"selectFile": "फ़ाइल चुनें",
"selectTags": "नोड टैग चुनें",
"tags": "नोड टैग",
"tagsLabel": "नोड टैग",
"updateSuccess": "नियम सफलतापूर्वक अपडेट किया गया"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "गोपनीयता नीति" "title": "गोपनीयता नीति"
}, },
"site": { "site": {
"customData": "कस्टम डेटा",
"customDataDescription": "कस्टम डेटा, साइट के कस्टम डेटा के लिए उपयोग किया जाता है",
"customHtml": "कस्टम HTML", "customHtml": "कस्टम HTML",
"customHtmlDescription": "साइट के bodyैग के नीचे इंजेक्ट करने के लिए कस्टम HTML कोड।", "customHtmlDescription": "साइट के bodyैग के नीचे इंजेक्ट करने के लिए कस्टम HTML कोड।",
"keywords": "कीवर्ड", "keywords": "कीवर्ड",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "खाता सक्षम करें", "accountEnable": "खाता सक्षम करें",
"actions": "क्रियाएँ", "actions": "क्रियाएँ",
"active": "सक्रिय",
"add": "जोड़ें", "add": "जोड़ें",
"administrator": "प्रशासक", "administrator": "प्रशासक",
"areaCode": "क्षेत्र कोड", "areaCode": "क्षेत्र कोड",
@@ -41,10 +42,12 @@
"email": "ईमेल", "email": "ईमेल",
"enable": "सक्षम करें", "enable": "सक्षम करें",
"expireTime": "समाप्ति समय", "expireTime": "समाप्ति समय",
"expired": "समाप्त",
"expiredAt": "समाप्ति तिथि", "expiredAt": "समाप्ति तिथि",
"failed": "असफल", "failed": "असफल",
"giftAmount": "उपहार राशि", "giftAmount": "उपहार राशि",
"giftAmountPlaceholder": "उपहार राशि दर्ज करें", "giftAmountPlaceholder": "उपहार राशि दर्ज करें",
"inactive": "निष्क्रिय",
"invalidEmailFormat": "अमान्य ईमेल प्रारूप", "invalidEmailFormat": "अमान्य ईमेल प्रारूप",
"inviteCode": "आमंत्रण कोड", "inviteCode": "आमंत्रण कोड",
"inviteCodePlaceholder": "आमंत्रण कोड दर्ज करें (उत्पन्न करने के लिए खाली छोड़ें)", "inviteCodePlaceholder": "आमंत्रण कोड दर्ज करें (उत्पन्न करने के लिए खाली छोड़ें)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "नया पासवर्ड दर्ज करें (वैकल्पिक)", "passwordPlaceholder": "नया पासवर्ड दर्ज करें (वैकल्पिक)",
"permanent": "स्थायी", "permanent": "स्थायी",
"pleaseEnterEmail": "कृपया ईमेल दर्ज करें", "pleaseEnterEmail": "कृपया ईमेल दर्ज करें",
"price": "कीमत",
"referer": "सिफारिशकर्ता", "referer": "सिफारिशकर्ता",
"refererId": "रेफरर आईडी", "refererId": "रेफरर आईडी",
"refererIdPlaceholder": "रेफरर आईडी दर्ज करें", "refererIdPlaceholder": "रेफरर आईडी दर्ज करें",
@@ -74,8 +78,12 @@
"searchIp": "आईपी पता खोजें", "searchIp": "आईपी पता खोजें",
"selectAuthType": "प्रमाणीकरण प्रकार चुनें", "selectAuthType": "प्रमाणीकरण प्रकार चुनें",
"speedLimit": "गति सीमा", "speedLimit": "गति सीमा",
"startTime": "शुरुआत का समय",
"status": "स्थिति",
"subscription": "सदस्यता", "subscription": "सदस्यता",
"subscriptionDetails": "सदस्यता विवरण", "subscriptionDetails": "सदस्यता विवरण",
"subscriptionId": "सदस्यता आईडी",
"subscriptionInfo": "सदस्यता जानकारी",
"subscriptionList": "सदस्यता सूची", "subscriptionList": "सदस्यता सूची",
"subscriptionLogs": "सदस्यता लॉग्स", "subscriptionLogs": "सदस्यता लॉग्स",
"subscriptionName": "सदस्यता नाम", "subscriptionName": "सदस्यता नाम",
@@ -89,6 +97,8 @@
"tradeNotifications": "व्यापार सूचनाएं", "tradeNotifications": "व्यापार सूचनाएं",
"trafficLimit": "ट्रैफिक सीमा", "trafficLimit": "ट्रैफिक सीमा",
"trafficLogs": "ट्रैफिक लॉग्स", "trafficLogs": "ट्रैफिक लॉग्स",
"trafficUsage": "ट्रैफ़िक उपयोग",
"unknown": "अज्ञात",
"unlimited": "असीमित", "unlimited": "असीमित",
"unverified": "असत्यापित", "unverified": "असत्यापित",
"update": "अपडेट", "update": "अपडेट",
@@ -98,11 +108,15 @@
"userAgent": "उपयोगकर्ता एजेंट", "userAgent": "उपयोगकर्ता एजेंट",
"userEmail": "उपयोगकर्ता ईमेल", "userEmail": "उपयोगकर्ता ईमेल",
"userEmailPlaceholder": "उपयोगकर्ता ईमेल दर्ज करें", "userEmailPlaceholder": "उपयोगकर्ता ईमेल दर्ज करें",
"userId": "उपयोगकर्ता आईडी",
"userInfo": "उपयोगकर्ता जानकारी",
"userList": "उपयोगकर्ता सूची", "userList": "उपयोगकर्ता सूची",
"userLogs": "लॉगिन इतिहास", "userLogs": "लॉगिन इतिहास",
"userName": "उपयोगकर्ता पहचानकर्ता", "userName": "उपयोगकर्ता पहचानकर्ता",
"userOrders": "ऑर्डर", "userOrders": "ऑर्डर",
"userProfile": "प्रोफ़ाइल", "userProfile": "प्रोफ़ाइल",
"userSubscriptions": "सदस्यताएँ", "userSubscriptions": "सदस्यताएँ",
"verified": "सत्यापित" "username": "उपयोगकर्ता नाम",
"verified": "सत्यापित",
"viewDetails": "विवरण देखें"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "Kérjük, adjon meg egy érvényes e-mail címet.", "email": "Kérjük, adjon meg egy érvényes e-mail címet.",
"existingAccount": "Már van fiókja?", "existingAccount": "Már van fiókja?",
"get": "Megkap", "get": "Megkap",
"invite": "Meghívókód", "invite": "Meghívó kód (opcionális)",
"message": "#### Tisztelt Felhasználó!\n\nKöszönjük érdeklődését és támogatását. Az oldal működési stratégiájának módosítása miatt lezártuk az új felhasználók regisztrációját. Ez idő alatt a meglévő felhasználók használata nem lesz érintett.\n\nElkötelezettek vagyunk abban, hogy jobb szolgáltatást és élményt nyújtsunk Önnek, ezért a regisztráció lezárása alatt átfogó rendszeroptimalizálást és funkciófrissítést hajtunk végre. A jövőben még jobb tartalommal és szolgáltatásokkal várjuk Önt.\n\nKérjük, kövesse weboldalunkat és közösségi média platformjainkat, hogy megkapja a legfrissebb híreket és értesítéseket. Köszönjük megértését és támogatását.\n\nHa bármilyen kérdése van, vagy segítségre van szüksége, kérjük, forduljon ügyfélszolgálati csapatunkhoz.\n\n**Még egyszer köszönjük támogatását és megértését.**", "message": "#### Tisztelt Felhasználó!\n\nKöszönjük érdeklődését és támogatását. Az oldal működési stratégiájának módosítása miatt lezártuk az új felhasználók regisztrációját. Ez idő alatt a meglévő felhasználók használata nem lesz érintett.\n\nElkötelezettek vagyunk abban, hogy jobb szolgáltatást és élményt nyújtsunk Önnek, ezért a regisztráció lezárása alatt átfogó rendszeroptimalizálást és funkciófrissítést hajtunk végre. A jövőben még jobb tartalommal és szolgáltatásokkal várjuk Önt.\n\nKérjük, kövesse weboldalunkat és közösségi média platformjainkat, hogy megkapja a legfrissebb híreket és értesítéseket. Köszönjük megértését és támogatását.\n\nHa bármilyen kérdése van, vagy segítségre van szüksége, kérjük, forduljon ügyfélszolgálati csapatunkhoz.\n\n**Még egyszer köszönjük támogatását és megértését.**",
"passwordMismatch": "A két jelszó nem egyezik meg", "passwordMismatch": "A két jelszó nem egyezik meg",
"success": "Sikeres regisztráció, automatikusan bejelentkezett!", "success": "Sikeres regisztráció, automatikusan bejelentkezett!",
+2
View File
@@ -39,6 +39,8 @@
"status": "Állapot", "status": "Állapot",
"subject": "Tárgy", "subject": "Tárgy",
"template": "Sablon", "template": "Sablon",
"traffic_exceed_email_template": "Forgalmi Túllépés Értesítő Sablon",
"traffic_exceed_email_templateDescription": "A {after}.variable{before} helyettesítők tényleges adatokkal lesznek helyettesítve. Győződjön meg róla, hogy ezeket a változókat megőrzi.",
"verify_email_template": "Ellenőrző Email Sablon", "verify_email_template": "Ellenőrző Email Sablon",
"verify_email_templateDescription": "A {after}.variable{before} helyőrzőket tényleges adatokkal fogjuk helyettesíteni. Ügyeljen arra, hogy ezeket a változókat megtartsa.", "verify_email_templateDescription": "A {after}.variable{before} helyőrzőket tényleges adatokkal fogjuk helyettesíteni. Ügyeljen arra, hogy ezeket a változókat megtartsa.",
"whitelistSuffixes": "Engedélyezett utótagok", "whitelistSuffixes": "Engedélyezett utótagok",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "ADS konfiguráció", "ADS Config": "ADS konfiguráció",
"Announcement Management": "Hirdetménykezelés", "Announcement Management": "Hirdetménykezelés",
"Apple": "Apple ID", "Apple": "Apple ID",
"Application Management": "Alkalmazáskezelés",
"Auth Control": "Hitelesítési vezérlés", "Auth Control": "Hitelesítési vezérlés",
"Coupon Management": "Kuponkezelés", "Coupon Management": "Kuponkezelés",
"Dashboard": "Irányítópult", "Dashboard": "Irányítópult",
@@ -16,6 +17,7 @@
"Order Management": "Rendeléskezelés", "Order Management": "Rendeléskezelés",
"Payment Config": "Fizetési beállítások", "Payment Config": "Fizetési beállítások",
"Phone Number": "Telefonszám", "Phone Number": "Telefonszám",
"Rule Management": "Szabálykezelés",
"Server": "Szolgáltatás", "Server": "Szolgáltatás",
"Server Management": "Szerverkezelés", "Server Management": "Szerverkezelés",
"Settings": "Beállítások", "Settings": "Beállítások",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "Elemzés...",
"appIcon": "Szabály Ikon",
"cancel": "Mégse",
"confirm": "Megerősít",
"confirmDelete": "Törlés megerősítése",
"create": "Szabály hozzáadása",
"createRule": "Szabály hozzáadása",
"createSuccess": "A szabály sikeresen létrejött",
"createdAt": "Létrehozva",
"delete": "Törlés",
"deleteSuccess": "A szabály sikeresen törölve",
"deleteWarning": "Biztosan törölni szeretné ezt a szabályt? Ez a művelet nem vonható vissza.",
"description": "Szabály leírása",
"downloadTemplate": "Sablon letöltése",
"edit": "Szerkesztés",
"editRule": "Szabály szerkesztése",
"enable": "Engedélyezés",
"enterIconUrl": "Adja meg vagy töltse fel az ikont",
"enterRuleName": "Adja meg a szabály nevét",
"enterRules": "Adja meg a szabály tartalmát, soronként egyet",
"import": "Importálás",
"importFailed": "Importálás sikertelen",
"importSuccess": "Importálás sikeres",
"importYaml": "YAML importálása",
"importYamlDescription": "Szabályok importálása YAML fájlból, a rendszer automatikusan létrehozza a szabálycsoportokat a politikai csoportnevek alapján",
"importYamlRules": "YAML szabályok importálása",
"importing": "Importálás...",
"invalidYamlFormat": "Érvénytelen YAML formátum, hiányzik a szabályok mező",
"name": "Szabály neve",
"noValidRules": "Nincsenek érvényes szabályok",
"pleaseUploadFile": "Kérjük, töltsön fel egy YAML fájlt",
"preview": "Előnézet",
"rules": "Szabály tartalom",
"rulesFormat": "Szabály formátum: szabály típusa, egyezési tartalom, [politika], ahol a politika opcionális.\nHa a politika nincs megadva, az aktuális szabálycsoport neve automatikusan felhasználásra kerül. Példák:",
"rulesLabel": "Szabály tartalom",
"searchRule": "Szabály név keresése",
"selectFile": "Fájl kiválasztása",
"selectTags": "Válassza ki a csomópont címkéket",
"tags": "Csomópont címkék",
"tagsLabel": "Csomópont címkék",
"updateSuccess": "A szabály sikeresen frissítve"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "Adatvédelmi irányelvek" "title": "Adatvédelmi irányelvek"
}, },
"site": { "site": {
"customData": "Egyedi adatok",
"customDataDescription": "Egyedi adatok, a webhely egyedi adatainak használatára",
"customHtml": "Egyedi HTML", "customHtml": "Egyedi HTML",
"customHtmlDescription": "Egyedi HTML kód, amelyet a webhely bodyímkéjének aljára kell beilleszteni.", "customHtmlDescription": "Egyedi HTML kód, amelyet a webhely bodyímkéjének aljára kell beilleszteni.",
"keywords": "Kulcsszavak", "keywords": "Kulcsszavak",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "Fiók engedélyezése", "accountEnable": "Fiók engedélyezése",
"actions": "műveletek", "actions": "műveletek",
"active": "Aktív",
"add": "Hozzáadás", "add": "Hozzáadás",
"administrator": "Rendszergazda", "administrator": "Rendszergazda",
"areaCode": "Körzetszám", "areaCode": "Körzetszám",
@@ -41,10 +42,12 @@
"email": "e-mail", "email": "e-mail",
"enable": "Engedélyezés", "enable": "Engedélyezés",
"expireTime": "Lejárati idő", "expireTime": "Lejárati idő",
"expired": "Lejárt",
"expiredAt": "Lejárati dátum", "expiredAt": "Lejárati dátum",
"failed": "Sikertelen", "failed": "Sikertelen",
"giftAmount": "Ajándék Összeg", "giftAmount": "Ajándék Összeg",
"giftAmountPlaceholder": "Adja meg az ajándék összegét", "giftAmountPlaceholder": "Adja meg az ajándék összegét",
"inactive": "Inaktív",
"invalidEmailFormat": "Érvénytelen e-mail formátum", "invalidEmailFormat": "Érvénytelen e-mail formátum",
"inviteCode": "Meghívókód", "inviteCode": "Meghívókód",
"inviteCodePlaceholder": "Adja meg a meghívó kódot (hagyja üresen a generáláshoz)", "inviteCodePlaceholder": "Adja meg a meghívó kódot (hagyja üresen a generáláshoz)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "Adjon meg új jelszót (opcionális)", "passwordPlaceholder": "Adjon meg új jelszót (opcionális)",
"permanent": "Állandó", "permanent": "Állandó",
"pleaseEnterEmail": "Kérjük, adja meg az e-mail címet", "pleaseEnterEmail": "Kérjük, adja meg az e-mail címet",
"price": "Ár",
"referer": "Ajánló", "referer": "Ajánló",
"refererId": "Hivatkozó azonosító", "refererId": "Hivatkozó azonosító",
"refererIdPlaceholder": "Adja meg az ajánló azonosítóját", "refererIdPlaceholder": "Adja meg az ajánló azonosítóját",
@@ -74,8 +78,12 @@
"searchIp": "IP-cím keresése", "searchIp": "IP-cím keresése",
"selectAuthType": "Válassza ki az azonosítás típusát", "selectAuthType": "Válassza ki az azonosítás típusát",
"speedLimit": "Sebességhatár", "speedLimit": "Sebességhatár",
"startTime": "Kezdési idő",
"status": "Állapot",
"subscription": "Előfizetés", "subscription": "Előfizetés",
"subscriptionDetails": "Előfizetési részletek", "subscriptionDetails": "Előfizetési részletek",
"subscriptionId": "Előfizetés azonosítója",
"subscriptionInfo": "Előfizetés információ",
"subscriptionList": "Előfizetési lista", "subscriptionList": "Előfizetési lista",
"subscriptionLogs": "Előfizetési naplók", "subscriptionLogs": "Előfizetési naplók",
"subscriptionName": "Előfizetés neve", "subscriptionName": "Előfizetés neve",
@@ -89,6 +97,8 @@
"tradeNotifications": "Kereskedelmi értesítések", "tradeNotifications": "Kereskedelmi értesítések",
"trafficLimit": "Forgalmi korlát", "trafficLimit": "Forgalmi korlát",
"trafficLogs": "Forgalmi naplók", "trafficLogs": "Forgalmi naplók",
"trafficUsage": "Forgalmi használat",
"unknown": "Ismeretlen",
"unlimited": "Korlátlan", "unlimited": "Korlátlan",
"unverified": "Nem ellenőrzött", "unverified": "Nem ellenőrzött",
"update": "Frissítés", "update": "Frissítés",
@@ -98,11 +108,15 @@
"userAgent": "Felhasználói ügynök", "userAgent": "Felhasználói ügynök",
"userEmail": "Felhasználó e-mail", "userEmail": "Felhasználó e-mail",
"userEmailPlaceholder": "Adja meg a felhasználó e-mail címét", "userEmailPlaceholder": "Adja meg a felhasználó e-mail címét",
"userId": "Felhasználói azonosító",
"userInfo": "Felhasználói információ",
"userList": "Felhasználói lista", "userList": "Felhasználói lista",
"userLogs": "Bejelentkezési előzmények", "userLogs": "Bejelentkezési előzmények",
"userName": "Felhasználói azonosító", "userName": "Felhasználói azonosító",
"userOrders": "Rendelések", "userOrders": "Rendelések",
"userProfile": "Profil", "userProfile": "Profil",
"userSubscriptions": "Előfizetések", "userSubscriptions": "Előfizetések",
"verified": "Ellenőrzött" "username": "Felhasználónév",
"verified": "Ellenőrzött",
"viewDetails": "Részletek megtekintése"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "有効なメールアドレスを入力してください。", "email": "有効なメールアドレスを入力してください。",
"existingAccount": "すでにアカウントをお持ちですか?", "existingAccount": "すでにアカウントをお持ちですか?",
"get": "取得", "get": "取得",
"invite": "招待コード", "invite": "招待コード(任意)",
"message": "#### 親愛なるユーザーの皆様へ\n\n私たちのサイトにご関心とご支援をいただき、誠にありがとうございます。運営方針の調整に伴い、新規ユーザー登録機能を停止いたしました。この期間中、既存ユーザーのご利用には影響はございません。\n\nより良いサービスと体験を提供するため、登録停止期間中にシステムの全面的な最適化と機能のアップグレードを行います。今後、より質の高いコンテンツとサービスで皆様をお迎えいたします。\n\n最新の情報や通知を得るために、当社のウェブサイトやソーシャルメディアプラットフォームをご覧ください。ご理解とご支援に感謝いたします。\n\nご不明な点やご質問がございましたら、いつでもカスタマーサポートチームにお問い合わせください。\n\n**改めてご支援とご理解に感謝いたします。**", "message": "#### 親愛なるユーザーの皆様へ\n\n私たちのサイトにご関心とご支援をいただき、誠にありがとうございます。運営方針の調整に伴い、新規ユーザー登録機能を停止いたしました。この期間中、既存ユーザーのご利用には影響はございません。\n\nより良いサービスと体験を提供するため、登録停止期間中にシステムの全面的な最適化と機能のアップグレードを行います。今後、より質の高いコンテンツとサービスで皆様をお迎えいたします。\n\n最新の情報や通知を得るために、当社のウェブサイトやソーシャルメディアプラットフォームをご覧ください。ご理解とご支援に感謝いたします。\n\nご不明な点やご質問がございましたら、いつでもカスタマーサポートチームにお問い合わせください。\n\n**改めてご支援とご理解に感謝いたします。**",
"passwordMismatch": "パスワードが一致しません", "passwordMismatch": "パスワードが一致しません",
"success": "登録が成功しました。自動的にログインしました!", "success": "登録が成功しました。自動的にログインしました!",
+2
View File
@@ -39,6 +39,8 @@
"status": "ステータス", "status": "ステータス",
"subject": "件名", "subject": "件名",
"template": "テンプレート", "template": "テンプレート",
"traffic_exceed_email_template": "トラフィック超過通知テンプレート",
"traffic_exceed_email_templateDescription": "{after}と{before}の変数は実際のデータに置き換えられます。これらの変数を保持することを確認してください。",
"verify_email_template": "確認メールテンプレート", "verify_email_template": "確認メールテンプレート",
"verify_email_templateDescription": "{after}.variable{before} のプレースホルダーは実際のデータに置き換えられます。これらの変数を保持してください。", "verify_email_templateDescription": "{after}.variable{before} のプレースホルダーは実際のデータに置き換えられます。これらの変数を保持してください。",
"whitelistSuffixes": "ホワイトリストのサフィックス", "whitelistSuffixes": "ホワイトリストのサフィックス",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "ADS設定", "ADS Config": "ADS設定",
"Announcement Management": "お知らせ管理", "Announcement Management": "お知らせ管理",
"Apple": "Apple ID", "Apple": "Apple ID",
"Application Management": "アプリケーション管理",
"Auth Control": "認証管理", "Auth Control": "認証管理",
"Coupon Management": "クーポン管理", "Coupon Management": "クーポン管理",
"Dashboard": "ダッシュボード", "Dashboard": "ダッシュボード",
@@ -16,6 +17,7 @@
"Order Management": "注文管理", "Order Management": "注文管理",
"Payment Config": "支払い設定", "Payment Config": "支払い設定",
"Phone Number": "電話番号", "Phone Number": "電話番号",
"Rule Management": "ルール管理",
"Server": "サーバー", "Server": "サーバー",
"Server Management": "サーバー管理", "Server Management": "サーバー管理",
"Settings": "設定", "Settings": "設定",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "分析中...",
"appIcon": "ルールアイコン",
"cancel": "キャンセル",
"confirm": "確認",
"confirmDelete": "削除の確認",
"create": "ルールを追加",
"createRule": "ルールを追加",
"createSuccess": "ルールが正常に作成されました",
"createdAt": "作成日時",
"delete": "削除",
"deleteSuccess": "ルールが正常に削除されました",
"deleteWarning": "このルールを削除してもよろしいですか?この操作は元に戻せません。",
"description": "ルールの説明",
"downloadTemplate": "テンプレートをダウンロード",
"edit": "編集",
"editRule": "ルールを編集",
"enable": "有効化",
"enterIconUrl": "アイコンのURLを入力またはアップロード",
"enterRuleName": "ルール名を入力",
"enterRules": "ルールの内容を入力してください(1行ごと)",
"import": "インポート",
"importFailed": "インポートに失敗しました",
"importSuccess": "インポートが成功しました",
"importYaml": "YAMLをインポート",
"importYamlDescription": "YAMLファイルからルールをインポートします。システムはポリシーグループ名に基づいてルールグループを自動的に作成します。",
"importYamlRules": "YAMLルールをインポート",
"importing": "インポート中...",
"invalidYamlFormat": "無効なYAML形式です。ルールフィールドが欠けています。",
"name": "ルール名",
"noValidRules": "有効なルールが見つかりません",
"pleaseUploadFile": "YAMLファイルをアップロードしてください",
"preview": "プレビュー",
"rules": "ルールの内容",
"rulesFormat": "ルール形式: ルールタイプ, マッチ内容, [ポリシー](ポリシーはオプションです)。\nポリシーが指定されていない場合、現在のルールグループ名が自動的に使用されます。例:",
"rulesLabel": "ルールの内容",
"searchRule": "ルール名を検索",
"selectFile": "ファイルを選択",
"selectTags": "ノードタグを選択",
"tags": "ノードタグ",
"tagsLabel": "ノードタグ",
"updateSuccess": "ルールが正常に更新されました"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "プライバシーポリシー" "title": "プライバシーポリシー"
}, },
"site": { "site": {
"customData": "カスタムデータ",
"customDataDescription": "サイトのカスタムデータに使用されるカスタムデータ",
"customHtml": "カスタムHTML", "customHtml": "カスタムHTML",
"customHtmlDescription": "サイトの body タグの下部に挿入されるカスタム HTML コード。", "customHtmlDescription": "サイトの body タグの下部に挿入されるカスタム HTML コード。",
"keywords": "キーワード", "keywords": "キーワード",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "アカウント有効化", "accountEnable": "アカウント有効化",
"actions": "アクション", "actions": "アクション",
"active": "アクティブ",
"add": "追加", "add": "追加",
"administrator": "管理者", "administrator": "管理者",
"areaCode": "市外局番", "areaCode": "市外局番",
@@ -41,10 +42,12 @@
"email": "メールアドレス", "email": "メールアドレス",
"enable": "有効", "enable": "有効",
"expireTime": "有効期限", "expireTime": "有効期限",
"expired": "期限切れ",
"expiredAt": "有効期限", "expiredAt": "有効期限",
"failed": "失敗しました", "failed": "失敗しました",
"giftAmount": "ギフト金額", "giftAmount": "ギフト金額",
"giftAmountPlaceholder": "ギフト金額を入力してください", "giftAmountPlaceholder": "ギフト金額を入力してください",
"inactive": "非アクティブ",
"invalidEmailFormat": "無効なメール形式です", "invalidEmailFormat": "無効なメール形式です",
"inviteCode": "招待コード", "inviteCode": "招待コード",
"inviteCodePlaceholder": "招待コードを入力してください(生成するには空白のままにしてください)", "inviteCodePlaceholder": "招待コードを入力してください(生成するには空白のままにしてください)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "新しいパスワードを入力してください(任意)", "passwordPlaceholder": "新しいパスワードを入力してください(任意)",
"permanent": "永久", "permanent": "永久",
"pleaseEnterEmail": "メールアドレスを入力してください", "pleaseEnterEmail": "メールアドレスを入力してください",
"price": "価格",
"referer": "推薦者", "referer": "推薦者",
"refererId": "リファラーID", "refererId": "リファラーID",
"refererIdPlaceholder": "紹介者IDを入力してください", "refererIdPlaceholder": "紹介者IDを入力してください",
@@ -74,8 +78,12 @@
"searchIp": "IPアドレスを検索", "searchIp": "IPアドレスを検索",
"selectAuthType": "認証タイプを選択", "selectAuthType": "認証タイプを選択",
"speedLimit": "速度制限", "speedLimit": "速度制限",
"startTime": "開始時間",
"status": "ステータス",
"subscription": "サブスクリプション", "subscription": "サブスクリプション",
"subscriptionDetails": "サブスクリプションの詳細", "subscriptionDetails": "サブスクリプションの詳細",
"subscriptionId": "サブスクリプションID",
"subscriptionInfo": "サブスクリプション情報",
"subscriptionList": "購読リスト", "subscriptionList": "購読リスト",
"subscriptionLogs": "サブスクリプションログ", "subscriptionLogs": "サブスクリプションログ",
"subscriptionName": "サブスクリプション名", "subscriptionName": "サブスクリプション名",
@@ -89,6 +97,8 @@
"tradeNotifications": "取引通知", "tradeNotifications": "取引通知",
"trafficLimit": "トラフィック制限", "trafficLimit": "トラフィック制限",
"trafficLogs": "トラフィックログ", "trafficLogs": "トラフィックログ",
"trafficUsage": "トラフィック使用量",
"unknown": "不明",
"unlimited": "無制限", "unlimited": "無制限",
"unverified": "未確認", "unverified": "未確認",
"update": "更新", "update": "更新",
@@ -98,11 +108,15 @@
"userAgent": "ユーザーエージェント", "userAgent": "ユーザーエージェント",
"userEmail": "ユーザーのメール", "userEmail": "ユーザーのメール",
"userEmailPlaceholder": "ユーザーのメールアドレスを入力してください", "userEmailPlaceholder": "ユーザーのメールアドレスを入力してください",
"userId": "ユーザーID",
"userInfo": "ユーザー情報",
"userList": "ユーザーリスト", "userList": "ユーザーリスト",
"userLogs": "ログイン履歴", "userLogs": "ログイン履歴",
"userName": "ユーザー識別子", "userName": "ユーザー識別子",
"userOrders": "注文", "userOrders": "注文",
"userProfile": "プロフィール", "userProfile": "プロフィール",
"userSubscriptions": "サブスクリプション", "userSubscriptions": "サブスクリプション",
"verified": "確認済み" "username": "ユーザー名",
"verified": "確認済み",
"viewDetails": "詳細を見る"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "유효한 이메일 주소를 입력하세요.", "email": "유효한 이메일 주소를 입력하세요.",
"existingAccount": "이미 계정이 있으신가요?", "existingAccount": "이미 계정이 있으신가요?",
"get": "받기", "get": "받기",
"invite": "초대 코드", "invite": "초대 코드 (선택 사항)",
"message": "#### 존경하는 사용자님, 안녕하세요!\n\n저희에 대한 관심과 지원에 감사드립니다. 사이트 운영 전략의 조정으로 인해 신규 사용자 등록 기능을 닫았습니다. 이 기간 동안 기존 사용자의 사용에는 아무런 영향이 없습니다.\n\n저희는 더 나은 서비스와 경험을 제공하기 위해 등록이 닫힌 동안 시스템 최적화와 기능 업그레이드를 전면적으로 진행할 것입니다. 앞으로 더 나은 콘텐츠와 서비스로 여러분을 맞이하겠습니다.\n\n저희 웹사이트와 소셜 미디어 플랫폼을 주시하여 최신 동향과 공지를 받아보세요. 이해와 지원에 감사드립니다.\n\n궁금한 점이나 도움이 필요하시면 언제든지 고객 서비스 팀에 문의해 주세요.\n\n**다시 한번 지원과 이해에 감사드립니다.**", "message": "#### 존경하는 사용자님, 안녕하세요!\n\n저희에 대한 관심과 지원에 감사드립니다. 사이트 운영 전략의 조정으로 인해 신규 사용자 등록 기능을 닫았습니다. 이 기간 동안 기존 사용자의 사용에는 아무런 영향이 없습니다.\n\n저희는 더 나은 서비스와 경험을 제공하기 위해 등록이 닫힌 동안 시스템 최적화와 기능 업그레이드를 전면적으로 진행할 것입니다. 앞으로 더 나은 콘텐츠와 서비스로 여러분을 맞이하겠습니다.\n\n저희 웹사이트와 소셜 미디어 플랫폼을 주시하여 최신 동향과 공지를 받아보세요. 이해와 지원에 감사드립니다.\n\n궁금한 점이나 도움이 필요하시면 언제든지 고객 서비스 팀에 문의해 주세요.\n\n**다시 한번 지원과 이해에 감사드립니다.**",
"passwordMismatch": "비밀번호가 일치하지 않습니다.", "passwordMismatch": "비밀번호가 일치하지 않습니다.",
"success": "등록 성공, 자동으로 로그인되었습니다!", "success": "등록 성공, 자동으로 로그인되었습니다!",
+2
View File
@@ -39,6 +39,8 @@
"status": "상태", "status": "상태",
"subject": "제목", "subject": "제목",
"template": "템플릿", "template": "템플릿",
"traffic_exceed_email_template": "트래픽 초과 알림 템플릿",
"traffic_exceed_email_templateDescription": "{after}.variable{before} 자리표시는 실제 데이터로 대체됩니다. 이러한 변수를 유지해야 합니다.",
"verify_email_template": "이메일 인증 템플릿", "verify_email_template": "이메일 인증 템플릿",
"verify_email_templateDescription": "{after}.variable{before} 자리표시는 실제 데이터로 대체됩니다. 이 변수를 반드시 유지하십시오.", "verify_email_templateDescription": "{after}.variable{before} 자리표시는 실제 데이터로 대체됩니다. 이 변수를 반드시 유지하십시오.",
"whitelistSuffixes": "허용 목록 접미사", "whitelistSuffixes": "허용 목록 접미사",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "ADS 구성", "ADS Config": "ADS 구성",
"Announcement Management": "공지 관리", "Announcement Management": "공지 관리",
"Apple": "Apple ID", "Apple": "Apple ID",
"Application Management": "애플리케이션 관리",
"Auth Control": "인증 제어", "Auth Control": "인증 제어",
"Coupon Management": "쿠폰 관리", "Coupon Management": "쿠폰 관리",
"Dashboard": "대시보드", "Dashboard": "대시보드",
@@ -16,6 +17,7 @@
"Order Management": "주문 관리", "Order Management": "주문 관리",
"Payment Config": "결제 구성", "Payment Config": "결제 구성",
"Phone Number": "전화번호", "Phone Number": "전화번호",
"Rule Management": "규칙 관리",
"Server": "서버", "Server": "서버",
"Server Management": "서버 관리", "Server Management": "서버 관리",
"Settings": "설정", "Settings": "설정",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "분석 중...",
"appIcon": "규칙 아이콘",
"cancel": "취소",
"confirm": "확인",
"confirmDelete": "삭제 확인",
"create": "규칙 추가",
"createRule": "규칙 추가",
"createSuccess": "규칙이 성공적으로 생성되었습니다",
"createdAt": "생성일",
"delete": "삭제",
"deleteSuccess": "규칙이 성공적으로 삭제되었습니다",
"deleteWarning": "이 규칙을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.",
"description": "규칙 설명",
"downloadTemplate": "템플릿 다운로드",
"edit": "편집",
"editRule": "규칙 편집",
"enable": "활성화",
"enterIconUrl": "아이콘 URL을 입력하거나 업로드하세요",
"enterRuleName": "규칙 이름을 입력하세요",
"enterRules": "규칙 내용을 입력하세요, 한 줄에 하나씩",
"import": "가져오기",
"importFailed": "가져오기에 실패했습니다",
"importSuccess": "가져오기가 성공적으로 완료되었습니다",
"importYaml": "YAML 가져오기",
"importYamlDescription": "YAML 파일에서 규칙을 가져오며, 시스템이 정책 그룹 이름에 따라 규칙 그룹을 자동으로 생성합니다",
"importYamlRules": "YAML 규칙 가져오기",
"importing": "가져오는 중...",
"invalidYamlFormat": "잘못된 YAML 형식, 규칙 필드가 누락되었습니다",
"name": "규칙 이름",
"noValidRules": "유효한 규칙이 없습니다",
"pleaseUploadFile": "YAML 파일을 업로드해 주세요",
"preview": "미리보기",
"rules": "규칙 내용",
"rulesFormat": "규칙 형식: 규칙 유형, 일치하는 내용, [정책], 여기서 정책은 선택 사항입니다.\n정책이 지정되지 않으면 현재 규칙 그룹 이름이 자동으로 사용됩니다. 예시:",
"rulesLabel": "규칙 내용",
"searchRule": "규칙 이름 검색",
"selectFile": "파일 선택",
"selectTags": "노드 태그 선택",
"tags": "노드 태그",
"tagsLabel": "노드 태그",
"updateSuccess": "규칙이 성공적으로 업데이트되었습니다"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "개인정보 처리방침" "title": "개인정보 처리방침"
}, },
"site": { "site": {
"customData": "사용자 정의 데이터",
"customDataDescription": "사이트의 사용자 정의 데이터에 사용되는 사용자 정의 데이터",
"customHtml": "사용자 정의 HTML", "customHtml": "사용자 정의 HTML",
"customHtmlDescription": "사이트의 body그 하단에 삽입될 사용자 정의 HTML 코드입니다.", "customHtmlDescription": "사이트의 body그 하단에 삽입될 사용자 정의 HTML 코드입니다.",
"keywords": "키워드", "keywords": "키워드",
+15 -1
View File
@@ -1,6 +1,7 @@
{ {
"accountEnable": "계정 활성화", "accountEnable": "계정 활성화",
"actions": "작업", "actions": "작업",
"active": "활성",
"add": "추가", "add": "추가",
"administrator": "관리자", "administrator": "관리자",
"areaCode": "지역 코드", "areaCode": "지역 코드",
@@ -41,10 +42,12 @@
"email": "이메일", "email": "이메일",
"enable": "사용", "enable": "사용",
"expireTime": "만료 시간", "expireTime": "만료 시간",
"expired": "만료됨",
"expiredAt": "만료일", "expiredAt": "만료일",
"failed": "실패", "failed": "실패",
"giftAmount": "선물 금액", "giftAmount": "선물 금액",
"giftAmountPlaceholder": "선물 금액 입력", "giftAmountPlaceholder": "선물 금액 입력",
"inactive": "비활성",
"invalidEmailFormat": "잘못된 이메일 형식입니다", "invalidEmailFormat": "잘못된 이메일 형식입니다",
"inviteCode": "초대 코드", "inviteCode": "초대 코드",
"inviteCodePlaceholder": "초대 코드를 입력하세요 (생성을 원하시면 비워두세요)", "inviteCodePlaceholder": "초대 코드를 입력하세요 (생성을 원하시면 비워두세요)",
@@ -63,6 +66,7 @@
"passwordPlaceholder": "새 비밀번호 입력 (선택 사항)", "passwordPlaceholder": "새 비밀번호 입력 (선택 사항)",
"permanent": "영구적인", "permanent": "영구적인",
"pleaseEnterEmail": "이메일을 입력하세요", "pleaseEnterEmail": "이메일을 입력하세요",
"price": "가격",
"referer": "추천인", "referer": "추천인",
"refererId": "추천인 ID", "refererId": "추천인 ID",
"refererIdPlaceholder": "추천인 ID를 입력하세요", "refererIdPlaceholder": "추천인 ID를 입력하세요",
@@ -74,8 +78,12 @@
"searchIp": "IP 주소 검색", "searchIp": "IP 주소 검색",
"selectAuthType": "인증 유형 선택", "selectAuthType": "인증 유형 선택",
"speedLimit": "속도 제한", "speedLimit": "속도 제한",
"startTime": "시작 시간",
"status": "상태",
"subscription": "구독", "subscription": "구독",
"subscriptionDetails": "구독 세부 정보", "subscriptionDetails": "구독 세부 정보",
"subscriptionId": "구독 ID",
"subscriptionInfo": "구독 정보",
"subscriptionList": "구독 목록", "subscriptionList": "구독 목록",
"subscriptionLogs": "구독 로그", "subscriptionLogs": "구독 로그",
"subscriptionName": "구독 이름", "subscriptionName": "구독 이름",
@@ -89,6 +97,8 @@
"tradeNotifications": "거래 알림", "tradeNotifications": "거래 알림",
"trafficLimit": "트래픽 제한", "trafficLimit": "트래픽 제한",
"trafficLogs": "트래픽 로그", "trafficLogs": "트래픽 로그",
"trafficUsage": "트래픽 사용량",
"unknown": "알 수 없음",
"unlimited": "무제한", "unlimited": "무제한",
"unverified": "확인되지 않음", "unverified": "확인되지 않음",
"update": "업데이트", "update": "업데이트",
@@ -98,11 +108,15 @@
"userAgent": "사용자 에이전트", "userAgent": "사용자 에이전트",
"userEmail": "사용자 이메일", "userEmail": "사용자 이메일",
"userEmailPlaceholder": "사용자 이메일 입력", "userEmailPlaceholder": "사용자 이메일 입력",
"userId": "사용자 ID",
"userInfo": "사용자 정보",
"userList": "사용자 목록", "userList": "사용자 목록",
"userLogs": "로그인 기록", "userLogs": "로그인 기록",
"userName": "사용자 식별자", "userName": "사용자 식별자",
"userOrders": "주문", "userOrders": "주문",
"userProfile": "프로필", "userProfile": "프로필",
"userSubscriptions": "구독", "userSubscriptions": "구독",
"verified": "검증됨" "username": "사용자 이름",
"verified": "검증됨",
"viewDetails": "세부 정보 보기"
} }
+1 -1
View File
@@ -28,7 +28,7 @@
"email": "Vennligst skriv inn en gyldig e-postadresse.", "email": "Vennligst skriv inn en gyldig e-postadresse.",
"existingAccount": "Har du allerede en konto?", "existingAccount": "Har du allerede en konto?",
"get": "Få", "get": "Få",
"invite": "Invitasjonskode", "invite": "Invitasjonskode (valgfritt)",
"message": "#### Kjære bruker,\n\nTakk for din interesse og støtte. På grunn av justeringer i vår driftsstrategi har vi stengt for registrering av nye brukere. I denne perioden vil eksisterende brukere ikke bli påvirket.\n\nVi er forpliktet til å gi deg bedre service og opplevelse, og vil derfor gjennomføre en omfattende systemoptimalisering og funksjonsoppgradering mens registreringen er stengt. I fremtiden vil vi ønske deg velkommen med bedre innhold og tjenester.\n\nFølg med på vår nettside og sosiale medieplattformer for å få de siste oppdateringene og kunngjøringene. Takk for din forståelse og støtte.\n\nHvis du har spørsmål eller trenger hjelp, vennligst kontakt vårt kundeserviceteam.\n\n**Takk igjen for din støtte og forståelse.**", "message": "#### Kjære bruker,\n\nTakk for din interesse og støtte. På grunn av justeringer i vår driftsstrategi har vi stengt for registrering av nye brukere. I denne perioden vil eksisterende brukere ikke bli påvirket.\n\nVi er forpliktet til å gi deg bedre service og opplevelse, og vil derfor gjennomføre en omfattende systemoptimalisering og funksjonsoppgradering mens registreringen er stengt. I fremtiden vil vi ønske deg velkommen med bedre innhold og tjenester.\n\nFølg med på vår nettside og sosiale medieplattformer for å få de siste oppdateringene og kunngjøringene. Takk for din forståelse og støtte.\n\nHvis du har spørsmål eller trenger hjelp, vennligst kontakt vårt kundeserviceteam.\n\n**Takk igjen for din støtte og forståelse.**",
"passwordMismatch": "Passordene stemmer ikke overens", "passwordMismatch": "Passordene stemmer ikke overens",
"success": "Registrering vellykket, du er nå automatisk logget inn!", "success": "Registrering vellykket, du er nå automatisk logget inn!",
+2
View File
@@ -39,6 +39,8 @@
"status": "Status", "status": "Status",
"subject": "Emne", "subject": "Emne",
"template": "Mal", "template": "Mal",
"traffic_exceed_email_template": "Varsel om overskridelse av trafikk",
"traffic_exceed_email_templateDescription": "Plassholderne {after}.variable{before} vil bli erstattet med faktiske data. Sørg for å beholde disse variablene.",
"verify_email_template": "Verifikasjons-e-postmal", "verify_email_template": "Verifikasjons-e-postmal",
"verify_email_templateDescription": "Plassholderne {after}.variable{before} vil bli erstattet med faktiske data. Sørg for å beholde disse variablene.", "verify_email_templateDescription": "Plassholderne {after}.variable{before} vil bli erstattet med faktiske data. Sørg for å beholde disse variablene.",
"whitelistSuffixes": "Hvitelistesuffikser", "whitelistSuffixes": "Hvitelistesuffikser",
+2
View File
@@ -2,6 +2,7 @@
"ADS Config": "ADS-konfigurasjon", "ADS Config": "ADS-konfigurasjon",
"Announcement Management": "Kunngjøringsadministrasjon", "Announcement Management": "Kunngjøringsadministrasjon",
"Apple": "Apple-ID", "Apple": "Apple-ID",
"Application Management": "Applikasjonsadministrasjon",
"Auth Control": "Autentiseringskontroll", "Auth Control": "Autentiseringskontroll",
"Coupon Management": "Kupongadministrasjon", "Coupon Management": "Kupongadministrasjon",
"Dashboard": "Dashbord", "Dashboard": "Dashbord",
@@ -16,6 +17,7 @@
"Order Management": "Bestillingsadministrasjon", "Order Management": "Bestillingsadministrasjon",
"Payment Config": "Betalingskonfigurasjon", "Payment Config": "Betalingskonfigurasjon",
"Phone Number": "Telefonnummer", "Phone Number": "Telefonnummer",
"Rule Management": "Regeladministrasjon",
"Server": "Tjeneste", "Server": "Tjeneste",
"Server Management": "Serveradministrasjon", "Server Management": "Serveradministrasjon",
"Settings": "Innstillinger", "Settings": "Innstillinger",
+43
View File
@@ -0,0 +1,43 @@
{
"analyzing": "Analyserer...",
"appIcon": "Regelikon",
"cancel": "Avbryt",
"confirm": "Bekreft",
"confirmDelete": "Bekreft sletting",
"create": "Legg til regel",
"createRule": "Legg til regel",
"createSuccess": "Regel opprettet med suksess",
"createdAt": "Opprettet den",
"delete": "Slett",
"deleteSuccess": "Regel slettet med suksess",
"deleteWarning": "Er du sikker på at du vil slette denne regelen? Denne handlingen kan ikke angres.",
"description": "Regelbeskrivelse",
"downloadTemplate": "Last ned mal",
"edit": "Rediger",
"editRule": "Rediger regel",
"enable": "Aktiver",
"enterIconUrl": "Skriv inn eller last opp et ikon",
"enterRuleName": "Skriv inn regelnavn",
"enterRules": "Skriv inn regelinnhold, en per linje",
"import": "Importer",
"importFailed": "Import mislyktes",
"importSuccess": "Import vellykket",
"importYaml": "Importer YAML",
"importYamlDescription": "Importer regler fra YAML-fil, systemet vil automatisk opprette regelgrupper basert på policygruppens navn",
"importYamlRules": "Importer YAML-regler",
"importing": "Importer...",
"invalidYamlFormat": "Ugyldig YAML-format, mangler reglerfelt",
"name": "Regelnavn",
"noValidRules": "Ingen gyldige regler funnet",
"pleaseUploadFile": "Vennligst last opp en YAML-fil",
"preview": "Forhåndsvisning",
"rules": "Regelinnhold",
"rulesFormat": "Regelformat: regeltype, matchinnhold, [policy], der policy er valgfritt.\nHvis policy ikke er spesifisert, vil det nåværende regelgruppens navn bli brukt automatisk. Eksempler:",
"rulesLabel": "Regelinnhold",
"searchRule": "Søk etter regelnavn",
"selectFile": "Velg fil",
"selectTags": "Velg nodetagger",
"tags": "Nodetagger",
"tagsLabel": "Nodetagger",
"updateSuccess": "Regel oppdatert med suksess"
}
+2
View File
@@ -13,6 +13,8 @@
"title": "Personvernerklæring" "title": "Personvernerklæring"
}, },
"site": { "site": {
"customData": "Egendata",
"customDataDescription": "Egendata, brukt for egendata på nettstedet",
"customHtml": "Egendefinert HTML", "customHtml": "Egendefinert HTML",
"customHtmlDescription": "Egendefinert HTML-kode som skal settes inn i bunnen av nettstedets body-tag.", "customHtmlDescription": "Egendefinert HTML-kode som skal settes inn i bunnen av nettstedets body-tag.",
"keywords": "Nøkkelord", "keywords": "Nøkkelord",

Some files were not shown because too many files have changed in this diff Show More