route:cache 는 새 앱을 부팅해 라우트를 수집하고, 그 부팅의 확장 라우트 프로바이더는 DB 가 아니라 캐시된 활성 확장 목록을 읽는다. 그래서 rebuild 가 invalidate*StatusCache 보다 앞서면 방금 바뀐 상태가 빠진 채 라우트가 박제되고, 라우트 캐시에는 스캔 폴백이 없어 오류도 로그도 없이 404 가 된다. 무효화를 굽기 직전이 아니라 DB 상태 쓰기 직후로 올려, 같은 목록을 읽는 훅 매핑 캐시까지 함께 바로잡았다. update 경로는 Updating 전이 직후에 비우면 그 창의 오토로드 갱신이 확장을 비활성으로 판정하므로, 상태 복원 직후에 비운 뒤 훅 캐시를 다시 굽는다. 플러그인 라우트 프로바이더에는 활성 게이트가 없어 비활성 플러그인의 API 가 계속 응답했다. 화면·메뉴만 사라지고 기능은 살아 있는 상태였다. 모듈과 같은 기준을 적용했다. 실패 사유가 하위 계층에서 버려져 관리자 화면에 :error 자리표시자가 그대로 노출되던 문제도 고쳤다. 반환 경로를 깨지 않도록 배열 키 reason 과 뒤에 붙인 선택적 out 파라미터로 사유를 실어 올리고, 확장이 수명주기 훅에서 사유를 남길 수 있는 통로를 추가했다. 설치 경로의 광역 RuntimeException catch 는 도메인 예외로 좁혀 원본 키와 파라미터를 응답에 싣는다 — 상태코드 422 는 유지해 사용자 계약을 함께 바꾸지 않는다. 언어팩 화면은 프로덕션에서 예외 원문을 싣지 않는 것이 확정된 계약이므로, 자리를 일반 문구로 채우는 대신 치환 자리 자체를 제거했다. 원문은 종전대로 errors 통로를 거쳐 디버그 모드에서 도달한다.
68 lines
4.7 KiB
PHP
68 lines
4.7 KiB
PHP
<?php
|
|
|
|
return [
|
|
'fetch_success' => 'Language pack list retrieved.',
|
|
'fetch_failed' => 'Failed to load language pack list.',
|
|
'not_found' => 'Language pack not found.',
|
|
'install_success' => 'Language pack installed.',
|
|
'install_failed' => 'Failed to install language pack.',
|
|
'activate_success' => 'Language pack activated.',
|
|
'activate_failed' => 'Failed to activate language pack.',
|
|
'deactivate_success' => 'Language pack deactivated.',
|
|
'deactivate_failed' => 'Failed to deactivate language pack.',
|
|
'uninstall_success' => 'Language pack removed.',
|
|
'uninstall_failed' => 'Failed to remove language pack.',
|
|
'manifest_invalid' => 'language-pack.json validation failed.',
|
|
'check_updates_success' => 'Update check completed.',
|
|
'check_updates_failed' => 'Failed to check updates.',
|
|
'update_success' => 'Language pack updated.',
|
|
'update_failed' => 'Failed to update language pack.',
|
|
'refresh_cache_success' => 'Language pack cache refreshed.',
|
|
'refresh_cache_failed' => 'Failed to refresh language pack cache.',
|
|
'preview_success' => 'Manifest preview completed.',
|
|
'preview_failed' => 'Failed to preview manifest.',
|
|
|
|
'errors' => [
|
|
'manifest_not_found' => 'language-pack.json file not found in archive.',
|
|
'manifest_invalid_json' => 'language-pack.json contains invalid JSON.',
|
|
'php_outside_backend' => 'PHP files are only allowed at backend/{locale}/{group}.php (:file).',
|
|
'php_file_not_literal_array' => 'PHP files may only contain a translation array. Line :line of :file contains code that is not part of an array.',
|
|
'unsupported_file_type' => 'This file type cannot be included in a language pack (:file — :extension). Only json, php and md files are allowed.',
|
|
'symlink_not_allowed' => 'Language packs cannot contain symbolic links (:file).',
|
|
'auto_activate_requires_manage' => 'Activating the pack right after installation requires the language pack management permission. Installation proceeds normally without this option.',
|
|
'core_locale_missing' => 'A core language pack for ":locale" must be active first.',
|
|
'target_not_installed' => 'Target :scope (":target") is not installed.',
|
|
'target_inactive' => 'Target :scope (":target") is inactive. Activate it first.',
|
|
'target_version_too_old' => 'Target :scope (":target") version does not satisfy the required constraint (:constraint).',
|
|
'downgrade_blocked' => 'Downgrade blocked (:from → :to).',
|
|
'protected_pack' => 'Protected language packs cannot be deactivated or removed.',
|
|
'download_failed' => 'Failed to download the language pack from URL (:url): :error',
|
|
'download_url_not_public' => 'Language packs cannot be downloaded from internal network addresses (private IPs, localhost, etc.). Use a publicly reachable https address.',
|
|
'checksum_mismatch' => 'Checksum mismatch.',
|
|
'update_no_source' => 'No update source available (only GitHub-sourced packs can be updated).',
|
|
'update_already_latest' => 'Already on the latest version.',
|
|
'preview_invalid_manifest' => 'Manifest preview failed: invalid manifest file.',
|
|
'operation_in_progress' => 'Another operation is in progress for language pack (:identifier). Please try again after it completes.',
|
|
'bundled_not_found' => 'Bundled directory (lang-packs/_bundled/:identifier) does not exist.',
|
|
'slot_conflict' => 'Slot already has an active language pack (:current). Confirm replacement with :target.',
|
|
'directory_not_writable' => 'The language pack install directory (:path) is not writable. Grant write permission to the web server user (e.g. www-data). Example: sudo chgrp www-data :path && sudo chmod g+w :path',
|
|
'identifier_not_found' => 'Language pack not found (:identifier).',
|
|
'unsupported_source' => 'Unsupported source (:source) — use one of bundled, github, url.',
|
|
],
|
|
|
|
'validation' => [
|
|
'file_required' => 'Upload a language pack ZIP file.',
|
|
'file_invalid' => 'Uploaded file is not valid.',
|
|
'file_too_large' => 'File size must not exceed 10 MB.',
|
|
'file_not_zip' => 'Only ZIP archives are accepted.',
|
|
'github_url_required' => 'Enter a GitHub URL.',
|
|
'github_url_invalid' => 'Enter a valid URL.',
|
|
'github_url_format' => 'Must be a GitHub repository URL (e.g. https://github.com/owner/repo).',
|
|
'url_required' => 'Enter a download URL.',
|
|
'url_invalid' => 'Enter a valid URL.',
|
|
'checksum_invalid' => 'SHA-256 checksum must be 64 hex characters.',
|
|
'identifier_required' => 'Enter the language pack identifier.',
|
|
'identifier_invalid' => 'Identifier may contain letters, numbers, dots, underscores and hyphens only.',
|
|
],
|
|
];
|