@byline/i18n 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +373 -0
- package/README.md +166 -0
- package/dist/admin/en.js +424 -0
- package/dist/admin/fr.js +424 -0
- package/dist/admin/index.d.ts +44 -0
- package/dist/admin/index.js +27 -0
- package/dist/formatter.d.ts +40 -0
- package/dist/formatter.js +65 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +3 -0
- package/dist/merge.d.ts +39 -0
- package/dist/merge.js +58 -0
- package/dist/react/i18n-context.d.ts +29 -0
- package/dist/react/i18n-context.js +3 -0
- package/dist/react/i18n-provider.d.ts +31 -0
- package/dist/react/i18n-provider.js +38 -0
- package/dist/react/index.d.ts +24 -0
- package/dist/react/index.js +4 -0
- package/dist/react/language-menu.d.ts +15 -0
- package/dist/react/language-menu.js +78 -0
- package/dist/react/use-translation.d.ts +24 -0
- package/dist/react/use-translation.js +16 -0
- package/dist/resolve.d.ts +21 -0
- package/dist/resolve.js +28 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.js +1 -0
- package/package.json +100 -0
- package/src/admin/en.json +423 -0
- package/src/admin/fr.json +423 -0
- package/src/admin/index.test.node.ts +68 -0
- package/src/admin/index.ts +99 -0
- package/src/formatter.test.node.ts +163 -0
- package/src/formatter.ts +166 -0
- package/src/index.ts +47 -0
- package/src/merge.test.node.ts +85 -0
- package/src/merge.ts +135 -0
- package/src/react/i18n-context.ts +45 -0
- package/src/react/i18n-provider.tsx +76 -0
- package/src/react/index.ts +26 -0
- package/src/react/language-menu.tsx +115 -0
- package/src/react/use-translation.ts +45 -0
- package/src/resolve.test.node.ts +128 -0
- package/src/resolve.ts +84 -0
- package/src/types.ts +72 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Locale code — kept as a plain `string` so the package stays open to
|
|
10
|
+
* any BCP 47 tag (`en`, `pt-BR`, `zh-Hans-CN`). The host's
|
|
11
|
+
* `i18n.interface.locales` config is the canonical allow-list at
|
|
12
|
+
* runtime; the resolver / validator narrow against it.
|
|
13
|
+
*/
|
|
14
|
+
export type LocaleCode = string;
|
|
15
|
+
/**
|
|
16
|
+
* Lightweight locale definition used by `<LanguageMenu>` to render the
|
|
17
|
+
* dropdown. The `code` matches a string in `i18n.interface.locales`;
|
|
18
|
+
* the `nativeName` is what the user sees ("English", "Español",
|
|
19
|
+
* "Français", "Deutsch", "日本語").
|
|
20
|
+
*/
|
|
21
|
+
export interface LocaleDefinition {
|
|
22
|
+
code: LocaleCode;
|
|
23
|
+
nativeName: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Namespace string — convention is `byline-<package>` for Byline-shipped
|
|
27
|
+
* code and `<org>-<plugin>` for third-party plugins. The runtime treats
|
|
28
|
+
* namespaces as opaque keys.
|
|
29
|
+
*/
|
|
30
|
+
export type Namespace = string;
|
|
31
|
+
/**
|
|
32
|
+
* Message key inside a namespace — dot-segmented by convention
|
|
33
|
+
* (`chrome.sidebar.collapse`), but the runtime treats keys as opaque.
|
|
34
|
+
*/
|
|
35
|
+
export type MessageKey = string;
|
|
36
|
+
/**
|
|
37
|
+
* One namespace's translations for one locale — flat key → ICU
|
|
38
|
+
* MessageFormat-encoded string.
|
|
39
|
+
*/
|
|
40
|
+
export type NamespaceTranslations = Readonly<Record<MessageKey, string>>;
|
|
41
|
+
/**
|
|
42
|
+
* The complete translation registry: locale → namespace → key →
|
|
43
|
+
* ICU-encoded message. Built by `mergeTranslations(...)`, passed to
|
|
44
|
+
* `<I18nProvider>`, and validated at boot by `@byline/core`.
|
|
45
|
+
*
|
|
46
|
+
* Bundles are deliberately plain JSON-shaped data — no functions, no
|
|
47
|
+
* React, no per-key metadata — so they can be authored as `.json`
|
|
48
|
+
* files, published as standalone npm packages, and round-tripped
|
|
49
|
+
* through any translation tool. Authoring-time metadata
|
|
50
|
+
* (descriptions, plural hints, deprecation markers) is a deferred
|
|
51
|
+
* Phase 4 surface; see `docs/I18N.md`.
|
|
52
|
+
*/
|
|
53
|
+
export type TranslationBundle = Readonly<{
|
|
54
|
+
[locale: LocaleCode]: Readonly<{
|
|
55
|
+
[namespace: Namespace]: NamespaceTranslations;
|
|
56
|
+
}>;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Values argument to `t(key, values)`. `intl-messageformat` accepts
|
|
60
|
+
* strings, numbers, booleans, Dates, and React elements — but we narrow
|
|
61
|
+
* the public API to JSON-safe primitives + Date so the `t` return type
|
|
62
|
+
* stays `string`. Rich-element interpolation (e.g. inline links) goes
|
|
63
|
+
* through a separate `<Trans>` component (not part of the PR 1 surface).
|
|
64
|
+
*/
|
|
65
|
+
export type TranslationValues = Readonly<Record<string, string | number | boolean | Date | null>>;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/package.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@byline/i18n",
|
|
3
|
+
"private": false,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MPL-2.0",
|
|
6
|
+
"version": "2.6.0",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20.9.0"
|
|
9
|
+
},
|
|
10
|
+
"description": "Byline CMS admin interface i18n — translation registry, ICU formatter, React provider, language switcher",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"cms",
|
|
13
|
+
"headless cms",
|
|
14
|
+
"content management",
|
|
15
|
+
"i18n",
|
|
16
|
+
"internationalization",
|
|
17
|
+
"translations"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://github.com/Byline-CMS/bylinecms.dev",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/Byline-CMS/bylinecms.dev/issues"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/Byline-CMS/bylinecms.dev.git",
|
|
26
|
+
"directory": "packages/i18n"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist/",
|
|
30
|
+
"src/"
|
|
31
|
+
],
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js",
|
|
36
|
+
"main": "./dist/index.js",
|
|
37
|
+
"default": "./dist/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./react": {
|
|
40
|
+
"types": "./dist/react/index.d.ts",
|
|
41
|
+
"import": "./dist/react/index.js",
|
|
42
|
+
"main": "./dist/react/index.js",
|
|
43
|
+
"default": "./dist/react/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./admin": {
|
|
46
|
+
"types": "./dist/admin/index.d.ts",
|
|
47
|
+
"import": "./dist/admin/index.js",
|
|
48
|
+
"main": "./dist/admin/index.js",
|
|
49
|
+
"default": "./dist/admin/index.js"
|
|
50
|
+
},
|
|
51
|
+
"./package.json": "./package.json"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@formatjs/intl-localematcher": "^0.8.8",
|
|
55
|
+
"classnames": "^2.5.1",
|
|
56
|
+
"intl-messageformat": "^11.2.7",
|
|
57
|
+
"negotiator": "^1.0.0",
|
|
58
|
+
"npm-run-all": "^4.1.5",
|
|
59
|
+
"@byline/ui": "2.6.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"react": "^19.0.0",
|
|
63
|
+
"react-dom": "^19.0.0"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@biomejs/biome": "2.4.15",
|
|
67
|
+
"@rsbuild/plugin-react": "^2.0.0",
|
|
68
|
+
"@rslib/core": "^0.21.5",
|
|
69
|
+
"@types/negotiator": "^0.6.4",
|
|
70
|
+
"@types/node": "^25.9.1",
|
|
71
|
+
"@types/react": "19.2.15",
|
|
72
|
+
"@types/react-dom": "19.2.3",
|
|
73
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
74
|
+
"react": "19.2.6",
|
|
75
|
+
"react-dom": "19.2.6",
|
|
76
|
+
"rimraf": "^6.1.3",
|
|
77
|
+
"typescript": "6.0.3",
|
|
78
|
+
"vite": "^8.0.14",
|
|
79
|
+
"vitest": "^4.1.7"
|
|
80
|
+
},
|
|
81
|
+
"publishConfig": {
|
|
82
|
+
"access": "public",
|
|
83
|
+
"files": [
|
|
84
|
+
"dist/",
|
|
85
|
+
"src/"
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
"scripts": {
|
|
89
|
+
"dev": "run-p dev:*",
|
|
90
|
+
"dev:code": "rslib build --watch",
|
|
91
|
+
"build": "run-s build:*",
|
|
92
|
+
"build:clean": "node scripts/clean.js dist build",
|
|
93
|
+
"build:code": "rslib build",
|
|
94
|
+
"typecheck": "tsc --noEmit",
|
|
95
|
+
"clean": "node scripts/clean.js node_modules dist build types .turbo",
|
|
96
|
+
"lint": "biome check --write --unsafe --diagnostic-level=error",
|
|
97
|
+
"test": "vitest run --mode=node",
|
|
98
|
+
"test:watch": "vitest --mode=node"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
{
|
|
2
|
+
"common.actions.save": "Save",
|
|
3
|
+
"common.actions.cancel": "Cancel",
|
|
4
|
+
"common.actions.delete": "Delete",
|
|
5
|
+
"common.actions.confirm": "Confirm",
|
|
6
|
+
"common.actions.close": "Close",
|
|
7
|
+
"common.actions.edit": "Edit",
|
|
8
|
+
"common.actions.create": "Create",
|
|
9
|
+
"common.actions.duplicate": "Duplicate",
|
|
10
|
+
"common.actions.preview": "Preview",
|
|
11
|
+
"common.actions.publish": "Publish",
|
|
12
|
+
"common.actions.unpublish": "Unpublish",
|
|
13
|
+
"common.actions.restore": "Restore",
|
|
14
|
+
"common.actions.search": "Search",
|
|
15
|
+
"common.actions.select": "Select",
|
|
16
|
+
"common.pager.previous": "Previous",
|
|
17
|
+
"common.pager.next": "Next",
|
|
18
|
+
"common.pager.pageOf": "Page {page, number} of {total, number}",
|
|
19
|
+
"common.actions.signIn": "Sign In",
|
|
20
|
+
"common.actions.signOut": "Sign out",
|
|
21
|
+
"common.actions.signingOut": "Signing out…",
|
|
22
|
+
"common.actions.home": "Home",
|
|
23
|
+
"common.actions.tryAgain": "Try again",
|
|
24
|
+
"common.actions.goToHomepage": "Go to homepage",
|
|
25
|
+
"common.fields.email": "Email",
|
|
26
|
+
"common.fields.password": "Password",
|
|
27
|
+
"common.boolean.yes": "Yes",
|
|
28
|
+
"common.boolean.no": "No",
|
|
29
|
+
"common.notSet": "Not set",
|
|
30
|
+
"common.never": "Never",
|
|
31
|
+
"common.empty.noResults": "No results.",
|
|
32
|
+
"common.loading": "Loading…",
|
|
33
|
+
"common.status.draft": "Draft",
|
|
34
|
+
"common.status.published": "Published",
|
|
35
|
+
"common.status.archived": "Archived",
|
|
36
|
+
"language.menuLabel": "Change language",
|
|
37
|
+
"language.useBrowserDefault": "Use browser default",
|
|
38
|
+
"chrome.sidebar.collapse": "Collapse sidebar",
|
|
39
|
+
"chrome.sidebar.expand": "Expand sidebar",
|
|
40
|
+
"chrome.account": "Account",
|
|
41
|
+
"chrome.languageMenu": "Language",
|
|
42
|
+
"chrome.appBar.signedInAs": "Signed in as",
|
|
43
|
+
"chrome.menu.openAriaLabel": "Open admin menu",
|
|
44
|
+
"chrome.menu.dashboard": "Dashboard",
|
|
45
|
+
"chrome.menu.adminUsers": "Admin Users",
|
|
46
|
+
"chrome.menu.adminRoles": "Admin Roles",
|
|
47
|
+
"chrome.menu.permissions": "Permissions",
|
|
48
|
+
"chrome.preview.on": "Preview ON",
|
|
49
|
+
"chrome.preview.off": "Preview OFF",
|
|
50
|
+
"chrome.preview.enableAriaLabel": "Enable preview mode",
|
|
51
|
+
"chrome.preview.disableAriaLabel": "Disable preview mode",
|
|
52
|
+
"chrome.preview.onTitle": "Drafts are visible on the public site",
|
|
53
|
+
"chrome.preview.offTitle": "Public site shows published only",
|
|
54
|
+
"chrome.breadcrumbs.showHiddenAriaLabel": "Show hidden breadcrumbs",
|
|
55
|
+
"list.unread": "{count, plural, one {# unread} other {# unread}}",
|
|
56
|
+
"doc.publishedOn": "Published on {date, date, medium}",
|
|
57
|
+
"validation.required": "This field is required.",
|
|
58
|
+
"validation.tooShort": "Must be at least {min, number} characters.",
|
|
59
|
+
"validation.tooLong": "Must be at most {max, number} characters.",
|
|
60
|
+
"errors.unknown": "Something went wrong. Please try again.",
|
|
61
|
+
"common.errors.versionConflict": "Your account has been modified elsewhere since you opened this form. Reload to refresh and try again.",
|
|
62
|
+
"common.errors.accountNotFound": "Your admin account could not be found. Please sign in again.",
|
|
63
|
+
"common.errors.couldNotSave": "Could not save changes. Please try again.",
|
|
64
|
+
"common.feedback.saved": "Saved.",
|
|
65
|
+
"common.feedback.noChanges": "No changes to save.",
|
|
66
|
+
"auth.signIn.title": "Sign in",
|
|
67
|
+
"auth.signIn.description": "Sign in to the Byline admin.",
|
|
68
|
+
"auth.signIn.errors.empty": "Enter your email and password.",
|
|
69
|
+
"auth.signIn.errors.invalidCredentials": "Invalid credentials.",
|
|
70
|
+
"account.intro": "Manage your own profile and password.",
|
|
71
|
+
"account.sections.profile": "Profile",
|
|
72
|
+
"account.sections.password": "Password",
|
|
73
|
+
"account.sections.status": "Account Status",
|
|
74
|
+
"account.sections.preferences": "Preferences",
|
|
75
|
+
"account.editAriaLabel": "Edit {section}",
|
|
76
|
+
"account.profile.givenName": "Given name:",
|
|
77
|
+
"account.profile.familyName": "Family name:",
|
|
78
|
+
"account.profile.emailColon": "Email:",
|
|
79
|
+
"account.profile.username": "Username:",
|
|
80
|
+
"account.profile.created": "Created:",
|
|
81
|
+
"account.profile.updated": "Updated:",
|
|
82
|
+
"account.profile.lastLogin": "Last login:",
|
|
83
|
+
"account.profile.editButton": "Edit Profile",
|
|
84
|
+
"account.password.intro": "Change the password used to sign in to the admin. You'll need to enter your current password to confirm the change.",
|
|
85
|
+
"account.password.editButton": "Change Password",
|
|
86
|
+
"account.status.superAdmin": "Super admin:",
|
|
87
|
+
"account.status.emailVerified": "Email verified:",
|
|
88
|
+
"account.status.status": "Status:",
|
|
89
|
+
"account.status.enabled": "Enabled",
|
|
90
|
+
"account.status.disabled": "Disabled",
|
|
91
|
+
"account.status.help": "These flags are managed by an admin with the appropriate permissions and are not self-editable.",
|
|
92
|
+
"account.preferences.interfaceLanguage": "Interface language:",
|
|
93
|
+
"account.preferences.editButton": "Change Language",
|
|
94
|
+
"account.preferences.help": "The same setting is available in the language menu in the top bar.",
|
|
95
|
+
"account.update.fields.givenName": "Given name",
|
|
96
|
+
"account.update.fields.familyName": "Family name",
|
|
97
|
+
"account.update.fields.username": "Username",
|
|
98
|
+
"account.update.fields.usernameHelp": "Optional. Leave blank to clear.",
|
|
99
|
+
"account.update.errors.givenNameTooLong": "Given name must not exceed {max, number} characters",
|
|
100
|
+
"account.update.errors.familyNameTooLong": "Family name must not exceed {max, number} characters",
|
|
101
|
+
"account.update.errors.usernameTooLong": "Username must not exceed {max, number} characters",
|
|
102
|
+
"account.update.errors.invalidEmail": "Enter a valid email address",
|
|
103
|
+
"account.update.errors.emailTooLong": "Email must not exceed {max, number} characters",
|
|
104
|
+
"account.update.errors.emailInUse": "This email is already in use.",
|
|
105
|
+
"account.changePassword.intro": "Other active sessions will continue to work until their tokens expire. Sign out elsewhere if you suspect another device has been compromised.",
|
|
106
|
+
"account.changePassword.fields.current": "Current password",
|
|
107
|
+
"account.changePassword.fields.new": "New password",
|
|
108
|
+
"account.changePassword.fields.confirm": "Confirm new password",
|
|
109
|
+
"account.changePassword.errors.currentRequired": "Please enter your current password",
|
|
110
|
+
"account.changePassword.errors.confirmRequired": "Please confirm the new password",
|
|
111
|
+
"account.changePassword.errors.mismatch": "New passwords do not match",
|
|
112
|
+
"account.changePassword.errors.currentIncorrect": "Current password is incorrect.",
|
|
113
|
+
"account.changePassword.errors.couldNotChange": "Could not change the password. Please try again.",
|
|
114
|
+
"account.changePassword.feedback.updated": "Password updated.",
|
|
115
|
+
"dashboard.collectionDescription": "{label} collection",
|
|
116
|
+
"dashboard.totalCount": "{count, number} total",
|
|
117
|
+
"adminUsers.list.title": "Admin Users",
|
|
118
|
+
"adminUsers.list.columns.givenName": "Given Name",
|
|
119
|
+
"adminUsers.list.columns.familyName": "Family Name",
|
|
120
|
+
"adminUsers.list.columns.email": "Email",
|
|
121
|
+
"adminUsers.list.columns.updated": "Updated",
|
|
122
|
+
"adminUsers.list.columns.created": "Created",
|
|
123
|
+
"adminUsers.list.createAriaLabel": "Create New Admin User",
|
|
124
|
+
"adminUsers.list.searchPlaceholder": "Search by name or email",
|
|
125
|
+
"adminUsers.list.pagerTopAriaLabel": "Top Pager",
|
|
126
|
+
"adminUsers.list.pagerBottomAriaLabel": "Bottom Pager",
|
|
127
|
+
"adminUsers.list.newDrawerTitle": "New Admin User",
|
|
128
|
+
"adminUsers.list.createdToastTitle": "Admin user created",
|
|
129
|
+
"adminUsers.breadcrumbDetail": "User",
|
|
130
|
+
"adminUsers.detail.sections.account": "Account Details",
|
|
131
|
+
"adminUsers.detail.sections.roles": "Roles",
|
|
132
|
+
"adminUsers.detail.sections.password": "Password",
|
|
133
|
+
"adminUsers.detail.sections.delete": "Delete Admin User",
|
|
134
|
+
"adminUsers.detail.panels.update": "Account Details",
|
|
135
|
+
"adminUsers.detail.panels.setPassword": "Set Password",
|
|
136
|
+
"adminUsers.detail.panels.delete": "Delete Admin User",
|
|
137
|
+
"adminUsers.detail.panels.roles": "User Roles",
|
|
138
|
+
"adminUsers.detail.updateButton": "Update Details",
|
|
139
|
+
"adminUsers.detail.rolesEmpty": "No roles assigned.",
|
|
140
|
+
"adminUsers.detail.editRolesButton": "Edit Roles",
|
|
141
|
+
"adminUsers.detail.password.intro": "Set a new password for this user.",
|
|
142
|
+
"adminUsers.detail.password.setButton": "Set Password",
|
|
143
|
+
"adminUsers.detail.delete.intro": "Permanently delete this admin user.",
|
|
144
|
+
"adminUsers.detail.delete.button": "Delete Admin User",
|
|
145
|
+
"adminUsers.detail.rolesSavedToast": "Roles saved",
|
|
146
|
+
"adminUsers.detail.rolesAssignedDescription": "{count, plural, one {# role} other {# roles}} assigned to {email}.",
|
|
147
|
+
"adminUsers.delete.userLabel": "User:",
|
|
148
|
+
"adminUsers.delete.emailLabel": "Email:",
|
|
149
|
+
"adminUsers.delete.warning": "This will permanently delete the admin user. The action cannot be undone. Any active sessions will be invalidated at the next refresh.",
|
|
150
|
+
"adminUsers.delete.confirmButton": "Delete User",
|
|
151
|
+
"adminUsers.delete.errors.selfDelete": "You cannot delete your own admin account.",
|
|
152
|
+
"adminUsers.delete.errors.versionConflict": "This user has been modified elsewhere since you opened this dialog. Close and reload before trying again.",
|
|
153
|
+
"adminUsers.delete.errors.notFound": "This user has already been deleted.",
|
|
154
|
+
"adminUsers.delete.errors.fallback": "Could not delete this admin user. Please try again.",
|
|
155
|
+
"adminUsers.create.fields.password": "Initial password",
|
|
156
|
+
"adminUsers.create.fields.passwordHelp": "The user can change it from their own account after signing in.",
|
|
157
|
+
"adminUsers.create.fields.usernameHelp": "Optional.",
|
|
158
|
+
"adminUsers.create.flags.enabledLabel": "Enabled",
|
|
159
|
+
"adminUsers.create.flags.enabledHelp": "Disabled accounts cannot sign in.",
|
|
160
|
+
"adminUsers.create.flags.emailVerifiedLabel": "Email verified",
|
|
161
|
+
"adminUsers.create.flags.emailVerifiedHelp": "Skip the verification flow for this account.",
|
|
162
|
+
"adminUsers.create.flags.superAdminLabel": "Super admin",
|
|
163
|
+
"adminUsers.create.flags.superAdminHelp": "Super admins bypass every ability check — grant with care.",
|
|
164
|
+
"adminUsers.create.errors.fallback": "Could not create this admin user. Please try again.",
|
|
165
|
+
"adminUsers.update.errors.versionConflict": "This user has been modified elsewhere since you opened this form. Reload to get the latest values and try again.",
|
|
166
|
+
"adminUsers.update.errors.notFound": "This user no longer exists.",
|
|
167
|
+
"adminUsers.setPassword.intro": "Sets a new password for {email}. The user will need to sign in again with the new password.",
|
|
168
|
+
"adminUsers.setPassword.errors.fallback": "Could not set the password. Please try again.",
|
|
169
|
+
"adminUsers.roles.emptyCatalog": "No roles have been created yet. Create roles in /admin/roles first.",
|
|
170
|
+
"adminUsers.roles.errors.userNotFound": "This user no longer exists.",
|
|
171
|
+
"adminUsers.roles.errors.roleNotFound": "One or more selected roles no longer exist. Reload the page and try again.",
|
|
172
|
+
"adminUsers.roles.errors.fallback": "Could not save roles. Please try again.",
|
|
173
|
+
"routeError.titles.notFound": "Not Found",
|
|
174
|
+
"routeError.titles.validation": "Validation Error",
|
|
175
|
+
"routeError.titles.conflict": "Conflict",
|
|
176
|
+
"routeError.titles.invalidTransition": "Invalid Transition",
|
|
177
|
+
"routeError.titles.patchFailed": "Update Failed",
|
|
178
|
+
"routeError.titles.database": "Database Error",
|
|
179
|
+
"routeError.titles.storage": "Storage Error",
|
|
180
|
+
"routeError.titles.unhandled": "Unexpected Error",
|
|
181
|
+
"routeError.defaultMessage": "An unexpected error occurred. Please try again.",
|
|
182
|
+
"routeError.notFound.title": "Page Not Found",
|
|
183
|
+
"routeError.notFound.message": "The page you are looking for does not exist or has been moved.",
|
|
184
|
+
"adminRoles.list.title": "Admin Roles",
|
|
185
|
+
"adminRoles.list.empty": "No admin roles found",
|
|
186
|
+
"adminRoles.list.columns.name": "Name",
|
|
187
|
+
"adminRoles.list.columns.machineName": "Machine Name",
|
|
188
|
+
"adminRoles.list.columns.description": "Description",
|
|
189
|
+
"adminRoles.list.columns.created": "Created",
|
|
190
|
+
"adminRoles.list.createAriaLabel": "Create New Admin Role",
|
|
191
|
+
"adminRoles.list.newDrawerTitle": "New Admin Role",
|
|
192
|
+
"adminRoles.list.createdToastTitle": "Admin role created",
|
|
193
|
+
"adminRoles.breadcrumbDetail": "Role",
|
|
194
|
+
"adminRoles.list.saveOrder": "Save Order",
|
|
195
|
+
"adminRoles.list.orderSavedToast": "Order saved",
|
|
196
|
+
"adminRoles.list.orderFailedToast": "Could not save the new order",
|
|
197
|
+
"adminRoles.list.orderFailedDescription": "Please try again.",
|
|
198
|
+
"adminRoles.detail.title": "Role Details",
|
|
199
|
+
"adminRoles.detail.editDetailsButton": "Edit Details",
|
|
200
|
+
"adminRoles.detail.deleteButton": "Delete Role",
|
|
201
|
+
"adminRoles.detail.fields.name": "Name:",
|
|
202
|
+
"adminRoles.detail.fields.machineName": "Machine name:",
|
|
203
|
+
"adminRoles.detail.fields.description": "Description:",
|
|
204
|
+
"adminRoles.detail.fields.created": "Created:",
|
|
205
|
+
"adminRoles.detail.fields.updated": "Updated:",
|
|
206
|
+
"adminRoles.detail.panels.update": "Role Details",
|
|
207
|
+
"adminRoles.detail.panels.delete": "Delete Admin Role",
|
|
208
|
+
"adminRoles.detail.permissionsSavedToast": "Permissions saved",
|
|
209
|
+
"adminRoles.detail.permissionsSavedDescription": "{count, plural, one {# ability} other {# abilities}} granted to {role}.",
|
|
210
|
+
"adminRoles.delete.roleLabel": "Role:",
|
|
211
|
+
"adminRoles.delete.machineLabel": "Machine name:",
|
|
212
|
+
"adminRoles.delete.warning": "This will permanently delete the role. Any users assigned to it lose the role; any per-role ability grants are removed. The action cannot be undone.",
|
|
213
|
+
"adminRoles.delete.confirmButton": "Delete Role",
|
|
214
|
+
"adminRoles.delete.errors.versionConflict": "This role has been modified elsewhere since you opened this dialog. Close and reload before trying again.",
|
|
215
|
+
"adminRoles.delete.errors.notFound": "This role has already been deleted.",
|
|
216
|
+
"adminRoles.delete.errors.fallback": "Could not delete this role. Please try again.",
|
|
217
|
+
"adminRoles.fields.name": "Name",
|
|
218
|
+
"adminRoles.fields.machineName": "Machine name",
|
|
219
|
+
"adminRoles.fields.description": "Description",
|
|
220
|
+
"adminRoles.create.fields.nameHelp": "Human-readable label, e.g. 'Editor'.",
|
|
221
|
+
"adminRoles.create.fields.machineNameHelp": "Stable code-side handle, e.g. 'editor'. Cannot be changed later.",
|
|
222
|
+
"adminRoles.create.errors.nameRequired": "Name is required",
|
|
223
|
+
"adminRoles.create.errors.nameTooLong": "Name must not exceed {max, number} characters",
|
|
224
|
+
"adminRoles.create.errors.machineNameRequired": "Machine name is required",
|
|
225
|
+
"adminRoles.create.errors.machineNameTooLong": "Machine name must not exceed {max, number} characters",
|
|
226
|
+
"adminRoles.create.errors.machineNameInvalid": "Lowercase letters, numbers, hyphens, and underscores only",
|
|
227
|
+
"adminRoles.create.errors.descriptionTooLong": "Description must not exceed {max, number} characters",
|
|
228
|
+
"adminRoles.create.errors.machineNameInUse": "This machine name is already in use.",
|
|
229
|
+
"adminRoles.create.errors.fallback": "Could not create this admin role. Please try again.",
|
|
230
|
+
"adminRoles.update.fields.machineNameHelp": "The stable code-side handle. Cannot be changed after creation.",
|
|
231
|
+
"adminRoles.update.errors.versionConflict": "This role has been modified elsewhere since you opened this form. Reload to get the latest values and try again.",
|
|
232
|
+
"adminRoles.update.errors.notFound": "This role no longer exists.",
|
|
233
|
+
"adminRoles.permissions.modeAriaLabel": "Permissions mode",
|
|
234
|
+
"adminRoles.permissions.viewMode": "View",
|
|
235
|
+
"adminRoles.permissions.editMode": "Edit",
|
|
236
|
+
"adminRoles.permissions.selectAll": "Select all",
|
|
237
|
+
"adminRoles.permissions.clear": "Clear",
|
|
238
|
+
"adminRoles.permissions.groupCount": "{selected, number} of {total, number} {mode, select, edit {selected} other {granted}}",
|
|
239
|
+
"adminRoles.permissions.counter": "{selected, number} of {total, number} {mode, select, edit {selected} other {granted}} for {role}",
|
|
240
|
+
"adminRoles.permissions.errors.roleNotFound": "This role no longer exists.",
|
|
241
|
+
"adminRoles.permissions.errors.abilityUnregistered": "One or more selected abilities are no longer registered. Reload the page and try again.",
|
|
242
|
+
"adminRoles.permissions.errors.fallback": "Could not save permissions. Please try again.",
|
|
243
|
+
"adminPermissions.title": "Abilities Inspector",
|
|
244
|
+
"adminPermissions.countPill": "{count, number} registered",
|
|
245
|
+
"adminPermissions.lead": "Read-only view of every ability registered through bylineCore.abilities. Collections auto-register CRUD + workflow abilities; admin subsystems contribute their own keys at composition root via registerAdminAbilities.",
|
|
246
|
+
"adminPermissions.empty": "No abilities are registered.",
|
|
247
|
+
"adminPermissions.group.abilitiesCount": "{count, plural, one {# ability} other {# abilities}}",
|
|
248
|
+
"adminPermissions.row.holdersButton": "Holders",
|
|
249
|
+
"adminPermissions.row.hideButton": "Hide",
|
|
250
|
+
"adminPermissions.matrix.rolesTitle": "Roles ({count, number})",
|
|
251
|
+
"adminPermissions.matrix.rolesEmpty": "No role grants this ability.",
|
|
252
|
+
"adminPermissions.matrix.usersTitle": "Admin users ({count, number})",
|
|
253
|
+
"adminPermissions.matrix.usersEmpty": "No admin user holds this ability.",
|
|
254
|
+
"adminPermissions.source.collection": "collection",
|
|
255
|
+
"adminPermissions.source.admin": "admin",
|
|
256
|
+
"adminPermissions.source.plugin": "plugin",
|
|
257
|
+
"adminPermissions.source.core": "core",
|
|
258
|
+
"adminPermissions.source.unknown": "unknown",
|
|
259
|
+
"collections.list.statusFilterAll": "All",
|
|
260
|
+
"collections.list.createAriaLabel": "Create New",
|
|
261
|
+
"collections.list.searchPlaceholder": "Search",
|
|
262
|
+
"collections.list.pagerTopAriaLabel": "Top Pager",
|
|
263
|
+
"collections.list.pagerBottomAriaLabel": "Bottom Pager",
|
|
264
|
+
"collections.list.dragHandleAriaLabel": "Drag to reorder",
|
|
265
|
+
"collections.list.dragDisabledAriaLabel": "Drag disabled while filters or search are active",
|
|
266
|
+
"collections.list.sortManualOrderAriaLabel": "Sort by manual order",
|
|
267
|
+
"collections.list.reorderFailedToast": "Could not save the new order",
|
|
268
|
+
"collections.list.reorderFailedDescription": "Please try again.",
|
|
269
|
+
"collections.create.errorToastTitle": "{label} Creation",
|
|
270
|
+
"collections.create.errorToastDescription": "An error occurred while creating {label}.",
|
|
271
|
+
"collections.edit.statusUpdateTitle": "{label} Status Update",
|
|
272
|
+
"collections.edit.statusChangedDescription": "Status changed to \"{status}\".",
|
|
273
|
+
"collections.edit.statusChangeFailedDescription": "Failed to change status: {message}",
|
|
274
|
+
"collections.edit.unpublishTitle": "{label} Unpublish",
|
|
275
|
+
"collections.edit.unpublishedDescription": "Published version has been taken offline.",
|
|
276
|
+
"collections.edit.unpublishFailedDescription": "Failed to unpublish: {message}",
|
|
277
|
+
"collections.edit.duplicatedTitle": "{label} Duplicated",
|
|
278
|
+
"collections.edit.duplicateTitle": "{label} Duplicate",
|
|
279
|
+
"collections.edit.duplicatedAutoPathDescription": "Created with auto-generated path \"{path}\" (the preferred slug was already in use).",
|
|
280
|
+
"collections.edit.duplicatedPathDescription": "Created with path \"{path}\". Update the title and path in the new document.",
|
|
281
|
+
"collections.edit.duplicatedSuccessMessage": "{label} duplicated.",
|
|
282
|
+
"collections.edit.duplicateFailedDescription": "Failed to duplicate: {message}",
|
|
283
|
+
"collections.edit.copyToLocaleTitle": "{label} Copy to Locale",
|
|
284
|
+
"collections.edit.copiedFieldsDescription": "Copied {count, plural, one {# field} other {# fields}} from {source} to {target}.",
|
|
285
|
+
"collections.edit.copiedNoFieldsDescription": "No fields needed copying from {source} to {target} under the current rule.",
|
|
286
|
+
"collections.edit.copiedSuccessMessage": "Copied {source} → {target}.",
|
|
287
|
+
"collections.edit.copyFailedDescription": "Failed to copy: {message}",
|
|
288
|
+
"collections.edit.deleteTitle": "{label} Deletion",
|
|
289
|
+
"collections.edit.deletedDescription": "{label} has been deleted.",
|
|
290
|
+
"collections.edit.deleteFailedDescription": "Failed to delete: {message}",
|
|
291
|
+
"collections.edit.updateTitle": "{label} Update",
|
|
292
|
+
"collections.edit.updatedDescription": "Successfully updated {label}.",
|
|
293
|
+
"collections.edit.updateFailedDescription": "An error occurred while updating {label}.",
|
|
294
|
+
"collections.history.title": "{label} History",
|
|
295
|
+
"collections.history.compareAriaLabel": "Compare this version with the current version",
|
|
296
|
+
"collections.history.compareTitle": "Compare with current",
|
|
297
|
+
"collections.history.restoreButton": "Restore",
|
|
298
|
+
"collections.history.restoreButtonTitle": "Restore this version as the current draft",
|
|
299
|
+
"collections.history.restoreModalTitle": "Restore version",
|
|
300
|
+
"collections.restore.versionLabel": "Version:",
|
|
301
|
+
"collections.restore.createdLabel": "Created:",
|
|
302
|
+
"collections.restore.warning": "This will create a new draft version of this document with the content from version {version}, and that draft will become the current version. The existing versions (including any published version) are preserved in history. The restored draft will need to be published through the normal workflow.",
|
|
303
|
+
"collections.restore.confirmButton": "Restore as Draft",
|
|
304
|
+
"collections.restore.errors.alreadyCurrent": "This version is already the current version of the document.",
|
|
305
|
+
"collections.restore.errors.notFound": "The selected version could not be found. The history may be out of date.",
|
|
306
|
+
"collections.restore.errors.forbidden": "You do not have permission to restore versions for this collection.",
|
|
307
|
+
"collections.restore.errors.fallback": "Could not restore this version. Please try again.",
|
|
308
|
+
"collections.api.title": "{label} API",
|
|
309
|
+
"collections.viewMenu.contentLocaleLabel": "Content Locale:",
|
|
310
|
+
"collections.viewMenu.localeAll": "All",
|
|
311
|
+
"collections.viewMenu.depthLabel": "Depth:",
|
|
312
|
+
"collections.viewMenu.apiButton": "API",
|
|
313
|
+
"collections.preview.toastTitle": "Preview",
|
|
314
|
+
"collections.preview.failedDescription": "Could not enable preview mode: {message}",
|
|
315
|
+
"collections.preview.openAriaLabel": "Open preview",
|
|
316
|
+
"collections.preview.title": "Preview",
|
|
317
|
+
"collections.breadcrumbs.create": "Create",
|
|
318
|
+
"collections.breadcrumbs.history": "History",
|
|
319
|
+
"collections.list.createdToastTitle": "{label} Created",
|
|
320
|
+
"collections.list.createdToastDescription": "Successfully created {label}.",
|
|
321
|
+
"documentActions.copyToLocaleMenuItem": "Copy to Locale",
|
|
322
|
+
"documentActions.delete.title": "Delete Document",
|
|
323
|
+
"documentActions.delete.warning": "Warning: This action cannot be undone. Are you sure you want to delete this document?",
|
|
324
|
+
"documentActions.duplicate.title": "Duplicate Document",
|
|
325
|
+
"documentActions.duplicate.intro": "A new document will be created with all translations (if any) cloned from this one. After the duplicate is created you should:",
|
|
326
|
+
"documentActions.duplicate.bulletTitle": "Update the title of the document (including any translated versions). The title is currently suffixed with",
|
|
327
|
+
"documentActions.duplicate.bulletPath": "Review the system path in the path widget — the auto-generated path will reflect the suffixed title and is unlikely to be what you want long-term.",
|
|
328
|
+
"documentActions.duplicate.previewLabel": "Preview (current locale):",
|
|
329
|
+
"documentActions.duplicate.busyButton": "Duplicating…",
|
|
330
|
+
"documentActions.copyToLocale.title": "Copy to Locale",
|
|
331
|
+
"documentActions.copyToLocale.intro": "Copy this document's content from one locale to another. Non-localized fields are shared across locales and will not change.",
|
|
332
|
+
"documentActions.copyToLocale.fromLabel": "From:",
|
|
333
|
+
"documentActions.copyToLocale.toLabel": "To:",
|
|
334
|
+
"documentActions.copyToLocale.targetAriaLabel": "Target locale",
|
|
335
|
+
"documentActions.copyToLocale.overwriteLabel": "Overwrite existing field data in target locale",
|
|
336
|
+
"documentActions.copyToLocale.overwriteHelp": "Unchecked: only fill in target fields that are currently empty. Checked: replace every translated field with the source's value.",
|
|
337
|
+
"documentActions.copyToLocale.confirmButton": "Copy",
|
|
338
|
+
"documentActions.copyToLocale.busyButton": "Copying…",
|
|
339
|
+
"forms.status.label": "Status:",
|
|
340
|
+
"forms.status.lastModified": "Last modified:",
|
|
341
|
+
"forms.status.created": "Created:",
|
|
342
|
+
"forms.status.publishedLive": "A published version is currently live.",
|
|
343
|
+
"forms.status.publishedOn": "Published on {date, date, medium}",
|
|
344
|
+
"forms.heading.create": "Create",
|
|
345
|
+
"forms.heading.edit": "Edit",
|
|
346
|
+
"forms.heading.createLabel": "Create {label}",
|
|
347
|
+
"forms.heading.editLabel": "Edit {label}",
|
|
348
|
+
"forms.actions.uploading": "Uploading…",
|
|
349
|
+
"forms.actions.revertTo": "Revert to {label}",
|
|
350
|
+
"forms.uploadFailedFieldError": "Upload failed: {message}",
|
|
351
|
+
"forms.restoreWarnings.title": "This document was loaded with a best-effort reconstruction",
|
|
352
|
+
"forms.restoreWarnings.body": "The collection schema has changed since this document was last saved, and {count, plural, one {# field} other {# fields}} could not be restored against the current shape. The form below shows only the fields that match the new schema. Saving will overwrite the document with the new shape — any data that did not match will be lost. To preserve it, copy what you need before saving, or delete this document and recreate it. Errors:",
|
|
353
|
+
"forms.navigationGuard.title": "Leave without saving?",
|
|
354
|
+
"forms.navigationGuard.message": "Your changes have not been saved. If you leave now, you will lose your changes.",
|
|
355
|
+
"forms.navigationGuard.stayButton": "Stay on this page",
|
|
356
|
+
"forms.navigationGuard.leaveButton": "Leave anyway",
|
|
357
|
+
"pathWidget.label": "Path",
|
|
358
|
+
"pathWidget.suggestedHint": "Suggested: \"{formatted}\"",
|
|
359
|
+
"pathWidget.readOnlyHint": "Path is set in the default locale (\"{locale}\") and applies across translations.",
|
|
360
|
+
"pathWidget.willBeSavedAs": "Will be saved as \"{preview}\"",
|
|
361
|
+
"pathWidget.srDescription": "System-managed URL path for this document.",
|
|
362
|
+
"pathWidget.regenerateButton": "Regenerate from {field}",
|
|
363
|
+
"pathWidget.regenerateAriaLabel": "Regenerate path from {field} field",
|
|
364
|
+
"fields.blocks.addBlockAriaLabel": "Add block",
|
|
365
|
+
"fields.blocks.modalTitle": "Blocks",
|
|
366
|
+
"fields.array.addItemAriaLabel": "Add item",
|
|
367
|
+
"fields.relation.selectPickerTitle": "Select {label}",
|
|
368
|
+
"fields.relation.changeAriaLabel": "Change {label}",
|
|
369
|
+
"fields.relation.removeAriaLabel": "Remove {label}",
|
|
370
|
+
"fields.relation.selectButton": "Select {label}…",
|
|
371
|
+
"fields.relation.unknownError": "Relation field \"{name}\" targets unknown collection \"{target}\".",
|
|
372
|
+
"fields.relation.unknownHint": "Register the collection in your Byline config or correct the target path.",
|
|
373
|
+
"fields.relation.picker.searchPlaceholder": "Search",
|
|
374
|
+
"fields.relation.picker.empty": "No documents found",
|
|
375
|
+
"fields.relation.picker.loadFailed": "Failed to load documents",
|
|
376
|
+
"fields.file.empty": "No file selected",
|
|
377
|
+
"fields.file.downloadAriaLabel": "Download file",
|
|
378
|
+
"fields.file.removeAriaLabel": "Remove file",
|
|
379
|
+
"fields.file.openInNewTabAriaLabel": "Open {filename} in a new tab",
|
|
380
|
+
"fields.file.upload.zoneAriaLabel": "Upload file — drag and drop or click to browse",
|
|
381
|
+
"fields.file.upload.label": "Drop file here or",
|
|
382
|
+
"fields.file.upload.browse": "browse",
|
|
383
|
+
"fields.image.empty": "No image selected",
|
|
384
|
+
"fields.image.removeAriaLabel": "Remove image",
|
|
385
|
+
"fields.image.openLightboxAriaLabel": "Open full-size preview",
|
|
386
|
+
"fields.image.upload.zoneAriaLabel": "Upload image — drag and drop or click to browse",
|
|
387
|
+
"fields.image.upload.label": "Drop image here or",
|
|
388
|
+
"fields.image.upload.browse": "browse",
|
|
389
|
+
"fields.image.upload.hint": "JPEG, PNG, WebP, GIF, SVG, AVIF",
|
|
390
|
+
"fields.image.upload.processing": "Processing…",
|
|
391
|
+
"fields.image.upload.errors.notAnImage": "Please select an image file.",
|
|
392
|
+
"fields.image.upload.errors.cannotRead": "Could not read image. Please try a different file.",
|
|
393
|
+
"fields.fileMeta.filename": "Filename:",
|
|
394
|
+
"fields.fileMeta.original": "Original:",
|
|
395
|
+
"fields.fileMeta.type": "Type:",
|
|
396
|
+
"fields.fileMeta.size": "Size:",
|
|
397
|
+
"fields.fileMeta.status": "Status:",
|
|
398
|
+
"fields.fileMeta.storage": "Storage:",
|
|
399
|
+
"fields.fileMeta.path": "Path:",
|
|
400
|
+
"fields.fileMeta.pendingUpload": "Pending upload",
|
|
401
|
+
"fields.fileMeta.willUploadOnSave": "Will upload on save",
|
|
402
|
+
"fields.imageMeta.dimensions": "Dimensions:",
|
|
403
|
+
"fields.imageMeta.format": "Format:",
|
|
404
|
+
"fields.imageMeta.thumbnail": "Thumbnail:",
|
|
405
|
+
"fields.imageMeta.thumbnailGenerated": "Generated",
|
|
406
|
+
"fields.imageMeta.thumbnailPending": "Pending",
|
|
407
|
+
"fields.sortable.expandAriaLabel": "Expand item",
|
|
408
|
+
"fields.sortable.collapseAriaLabel": "Collapse item",
|
|
409
|
+
"fields.draggableMenu.addBelow": "Add Below",
|
|
410
|
+
"fields.draggableMenu.remove": "Remove",
|
|
411
|
+
"diffModal.title": "Version Comparison",
|
|
412
|
+
"diffModal.subtitleBefore": "Comparing",
|
|
413
|
+
"diffModal.subtitleAfter": "(left) against current version (right)",
|
|
414
|
+
"diffModal.closeAriaLabel": "Close comparison",
|
|
415
|
+
"diffModal.loading": "Loading version…",
|
|
416
|
+
"diffModal.loadFailed": "Failed to load version",
|
|
417
|
+
"diffModal.currentVersion": "Current version",
|
|
418
|
+
"statusBadge.publishedVersionLive": "A published version is live",
|
|
419
|
+
"presentation.formTabsAriaLabel": "Form tabs",
|
|
420
|
+
"validation.password.tooShort": "Password must be at least 8 characters long.",
|
|
421
|
+
"validation.password.tooLong": "Password must not exceed 128 characters.",
|
|
422
|
+
"validation.password.complexity": "Password must contain at least one uppercase letter, one lowercase letter, one number, and one character from the following: #?!@$%^&*-"
|
|
423
|
+
}
|