@salesforce/afv-skills 1.34.0 → 1.36.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/package.json +1 -1
- package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +239 -0
- package/skills/automation-sandbox-post-copy-config-generate/assets/config_template.json +21 -0
- package/skills/automation-sandbox-post-copy-config-generate/assets/json_schema.json +90 -0
- package/skills/automation-sandbox-post-copy-config-generate/examples/sample_sop_excerpt.md +31 -0
- package/skills/automation-sandbox-post-copy-config-generate/examples/sample_sop_to_config.json +50 -0
- package/skills/automation-sandbox-post-copy-config-generate/references/configuration_catalog.md +76 -0
- package/skills/automation-sandbox-post-copy-config-generate/references/sop_parsing_patterns.md +157 -0
- package/skills/automation-sandbox-post-copy-config-generate/references/source_format_handling.md +230 -0
- package/skills/dx-apexguru-scan/SKILL.md +403 -0
- package/skills/dx-apexguru-scan/examples/README.md +54 -0
- package/skills/dx-apexguru-scan/examples/sample-decoded-summary.json +176 -0
- package/skills/dx-apexguru-scan/examples/sample-full-no-runtime-response.json +26 -0
- package/skills/dx-apexguru-scan/examples/sample-succeeded-response.json +15 -0
- package/skills/dx-apexguru-scan/references/api-reference.md +81 -0
- package/skills/dx-apexguru-scan/references/authentication.md +134 -0
- package/skills/dx-apexguru-scan/references/error-handling.md +56 -0
- package/skills/dx-apexguru-scan/references/violation-catalog.md +28 -0
- package/skills/dx-apexguru-scan/scripts/build-zip.sh +87 -0
- package/skills/dx-apexguru-scan/scripts/decode-report.js +389 -0
- package/skills/dx-apexguru-scan/scripts/resolve-token.sh +151 -0
- package/skills/dx-apexguru-scan/scripts/run-scan.sh +153 -0
- package/skills/dx-apexguru-scan/scripts/scan.sh +96 -0
- package/skills/dx-apexguru-scan/scripts/validate-token.js +121 -0
- package/skills/dx-app-analytics-query/SKILL.md +2 -0
- package/skills/dx-devops-pipeline-manage/SKILL.md +263 -0
- package/skills/dx-devops-pipeline-manage/examples/common-workflows.md +177 -0
- package/skills/dx-devops-pipeline-manage/references/cli-commands.md +298 -0
- package/skills/dx-devops-pipeline-manage/references/parsing-patterns.md +134 -0
- package/skills/dx-devops-pipeline-manage/scripts/check-activation-ready.sh +34 -0
- package/skills/dx-devops-pipeline-manage/scripts/validate-org-type.sh +17 -0
- package/skills/dx-devops-pipeline-manage/scripts/verify-operation.sh +82 -0
- package/skills/dx-devops-promote/SKILL.md +214 -0
- package/skills/dx-devops-promote/examples/promotion-workflows.md +212 -0
- package/skills/dx-devops-promote/references/cli-commands.md +303 -0
- package/skills/experience-lwc-base-components-integrate/SKILL.md +176 -0
- package/skills/experience-lwc-base-components-integrate/references/lbc-expert-guidance.md +127 -0
- package/skills/experience-lwc-base-components-integrate/references/lightning-component-index.md +179 -0
- package/skills/experience-lwc-base-components-integrate/references/lightning-components.md +5429 -0
- package/skills/experience-lwc-base-components-integrate/scripts/extract-component-docs.sh +61 -0
- package/skills/experience-lwc-rtl-validate/SKILL.md +149 -0
- package/skills/experience-lwc-rtl-validate/references/rtl-expert.md +892 -0
- package/skills/experience-lwc-rtl-validate/scripts/scan-rtl-css.sh +206 -0
- package/skills/experience-lwc-typescript-migrate/SKILL.md +207 -0
- package/skills/experience-lwc-typescript-migrate/assets/dts-template.ts +15 -0
- package/skills/experience-lwc-typescript-migrate/assets/type-patterns.ts +44 -0
- package/skills/experience-lwc-typescript-migrate/scripts/find-consumers.sh +128 -0
- package/skills/experience-ui-bundle-localize/SKILL.md +323 -0
- package/skills/experience-ui-bundle-localize/references/gotchas.md +249 -0
- package/skills/experience-ui-bundle-localize/references/i18n-setup.md +169 -0
- package/skills/experience-ui-bundle-localize/references/interpolation.md +311 -0
- package/skills/experience-ui-bundle-localize/references/label-xml.md +282 -0
- package/skills/experience-ui-bundle-localize/references/verifying.md +219 -0
- package/skills/experience-ui-bundle-localize/scripts/check-i18n-wired.sh +195 -0
- package/skills/experience-ui-bundle-localize/scripts/check-manifest-registered.sh +100 -0
- package/skills/experience-ui-bundle-localize/scripts/check-org-api-version.sh +40 -0
- package/skills/experience-ui-bundle-localize/scripts/detect-bundle-type.sh +57 -0
- package/skills/experience-ui-bundle-site-generate/SKILL.md +3 -0
- package/skills/mobile-apps-create/SKILL.md +1 -3
- package/skills/platform-custom-lightning-type-generate/SKILL.md +3 -0
- package/skills/platform-custom-lightning-type-generate/assets/primitive-types-and-constraints.md +1 -1
- package/skills/platform-mcp-tool-widget-coordinate/SKILL.md +250 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/action-name-source-prompt.md +74 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/apex-invocable-source-prompt.md +90 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-source-prompt.md +191 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/pasted-tool-output-prompt.md +85 -0
- package/skills/platform-mcp-tool-widget-coordinate/references/build-plan-format.md +74 -0
- package/skills/platform-mcp-tool-widget-coordinate/references/mcp-tool-output-discovery.md +184 -0
- package/skills/platform-mcp-tool-widget-coordinate/references/two-clt-modeling.md +128 -0
- package/skills/platform-mcp-tool-widget-coordinate/references/validation-gates.md +181 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# Label XML: Custom Labels and translation metadata shapes
|
|
2
|
+
|
|
3
|
+
This covers the two metadata XML files you author: the English base labels and the per-language translations.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Custom Labels: `force-app/main/default/labels/CustomLabels.labels-meta.xml`
|
|
8
|
+
|
|
9
|
+
This holds the **English base labels**: the source of truth for label content.
|
|
10
|
+
|
|
11
|
+
### Structure
|
|
12
|
+
|
|
13
|
+
```xml
|
|
14
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
15
|
+
<CustomLabels xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
16
|
+
<labels>
|
|
17
|
+
<fullName>Welcome_Text</fullName>
|
|
18
|
+
<language>en_US</language>
|
|
19
|
+
<protected>false</protected>
|
|
20
|
+
<shortDescription>Welcome banner heading</shortDescription>
|
|
21
|
+
<value>Welcome</value>
|
|
22
|
+
</labels>
|
|
23
|
+
<labels>
|
|
24
|
+
<fullName>Save_Button</fullName>
|
|
25
|
+
<language>en_US</language>
|
|
26
|
+
<protected>false</protected>
|
|
27
|
+
<shortDescription>Save button label</shortDescription>
|
|
28
|
+
<value>Save</value>
|
|
29
|
+
</labels>
|
|
30
|
+
</CustomLabels>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Fields
|
|
34
|
+
|
|
35
|
+
| Field | Purpose | Notes |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `<fullName>` | The label's API name | Used in `t("Key")` calls and the manifest (`"c:Welcome_Text"`). PascalCase, descriptive, unique. |
|
|
38
|
+
| `<language>` | Language code | Always `en_US` for the base label file. |
|
|
39
|
+
| `<protected>` | Managed package protection | Always `false` for custom labels in your org (you can edit them). |
|
|
40
|
+
| `<shortDescription>` | Internal description | For translators/developers, not shown to users. Describe what the label is for. |
|
|
41
|
+
| `<value>` | The English text | What the user sees. Can include `{0}`, `{1}` placeholders for interpolation. |
|
|
42
|
+
|
|
43
|
+
### Key naming conventions
|
|
44
|
+
|
|
45
|
+
Choose keys that are:
|
|
46
|
+
- **Descriptive**: `Welcome_Text` is better than `Label1`
|
|
47
|
+
- **Context-aware**: `Save_Button` vs `Save_Failed_Message` (same verb, different role)
|
|
48
|
+
- **Unique**: two labels shouldn't share a key even if the current text happens to match
|
|
49
|
+
|
|
50
|
+
Format: `<Context>_<Role>` in PascalCase with underscores between parts.
|
|
51
|
+
|
|
52
|
+
**Examples:**
|
|
53
|
+
- `"Welcome"` → `Welcome_Text` or `Welcome_Heading`
|
|
54
|
+
- `"Save"` → `Save_Button`
|
|
55
|
+
- `"Failed to save {0}: {1}"` → `Save_Failed_Message`
|
|
56
|
+
- `"Showing {0} of {1} records"` → `Record_Count_Display`
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Translations: `force-app/main/default/translations/<locale>.translation-meta.xml`
|
|
61
|
+
|
|
62
|
+
One file per translated language (e.g., `es.translation-meta.xml` for Spanish, `fr.translation-meta.xml` for French, `ja.translation-meta.xml` for Japanese).
|
|
63
|
+
|
|
64
|
+
### Structure
|
|
65
|
+
|
|
66
|
+
```xml
|
|
67
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
68
|
+
<Translations xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
69
|
+
<customLabels>
|
|
70
|
+
<label>Bienvenido</label>
|
|
71
|
+
<name>Welcome_Text</name>
|
|
72
|
+
</customLabels>
|
|
73
|
+
<customLabels>
|
|
74
|
+
<label>Guardar</label>
|
|
75
|
+
<name>Save_Button</name>
|
|
76
|
+
</customLabels>
|
|
77
|
+
</Translations>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Fields
|
|
81
|
+
|
|
82
|
+
| Field | Purpose | Notes |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `<name>` | The label's API name | Must exactly match the `<fullName>` in `CustomLabels.labels-meta.xml`. |
|
|
85
|
+
| `<label>` | The translated text | What the user sees in this language. Preserve `{0}`, `{1}` placeholders. |
|
|
86
|
+
|
|
87
|
+
### File naming
|
|
88
|
+
|
|
89
|
+
The filename is `<locale>.translation-meta.xml`, where `<locale>` is the Salesforce Language code:
|
|
90
|
+
- `es.translation-meta.xml`: Spanish
|
|
91
|
+
- `fr.translation-meta.xml`: French
|
|
92
|
+
- `de.translation-meta.xml`: German
|
|
93
|
+
- `ja.translation-meta.xml`: Japanese
|
|
94
|
+
- `pt_BR.translation-meta.xml`: Portuguese (Brazil)
|
|
95
|
+
- `zh_CN.translation-meta.xml`: Chinese (Simplified)
|
|
96
|
+
- `zh_TW.translation-meta.xml`: Chinese (Traditional)
|
|
97
|
+
|
|
98
|
+
See Salesforce's [Supported Languages](https://help.salesforce.com/s/articleView?id=sf.faq_getstart_what_languages_does.htm) for the full list.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## How translations are authored
|
|
103
|
+
|
|
104
|
+
You have two options:
|
|
105
|
+
|
|
106
|
+
### 1. Hand-edit the XML (for small apps)
|
|
107
|
+
|
|
108
|
+
Create the `<locale>.translation-meta.xml` file, add one `<customLabels>` block per label, and type the translations directly. Good for a handful of labels or prototyping.
|
|
109
|
+
|
|
110
|
+
### 2. Use Translation Workbench (for scale)
|
|
111
|
+
|
|
112
|
+
Salesforce's **Translation Workbench** is the in-org UI where translators enter translations, which you then pull down as deployable `.translation-meta.xml` files.
|
|
113
|
+
|
|
114
|
+
**Workflow:**
|
|
115
|
+
1. **Enable Translation Workbench**, Setup → Translation Workbench → Translation Settings → Enable
|
|
116
|
+
2. **Add languages**, same Settings page → Add the languages you plan to support
|
|
117
|
+
3. **Enter translations**, Setup → Translation Workbench → Translate → pick:
|
|
118
|
+
- **Setup Component:** Custom Label
|
|
119
|
+
- **Language:** the target language
|
|
120
|
+
- **Label:** the label to translate
|
|
121
|
+
- Type the translation, Save
|
|
122
|
+
4. **Retrieve as metadata**, pull the translations into your project:
|
|
123
|
+
```bash
|
|
124
|
+
sf project retrieve start --metadata Translations:es
|
|
125
|
+
sf project retrieve start --metadata Translations:fr
|
|
126
|
+
# etc., one per language
|
|
127
|
+
```
|
|
128
|
+
The CLI writes the `.translation-meta.xml` files to `force-app/main/default/translations/`.
|
|
129
|
+
|
|
130
|
+
Reference: [Translation Workbench overview](https://help.salesforce.com/s/articleView?id=sf.customize_wbench.htm)
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Namespace:Key format
|
|
135
|
+
|
|
136
|
+
In the **manifest** (`src/i18n/label-manifest.ts`) and some SDK contexts, labels are written as `"namespace:Key"`:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
export const labelManifest = [
|
|
140
|
+
"c:Welcome_Text",
|
|
141
|
+
"c:Save_Button",
|
|
142
|
+
];
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
- `c` = the custom label namespace (your org's labels)
|
|
146
|
+
- `Welcome_Text` = the `<fullName>` from `CustomLabels.labels-meta.xml`
|
|
147
|
+
|
|
148
|
+
Other namespaces exist (e.g., `LightningDatatable` for framework-shipped labels), but most bundles only use `c`.
|
|
149
|
+
|
|
150
|
+
In component code, the namespace is usually implicit (set via `defaultNS: "c"` in the init), so you call `t("Welcome_Text")` not `t("c:Welcome_Text")`.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Interpolation: `{0}`, `{1}` placeholders
|
|
155
|
+
|
|
156
|
+
Labels can include **positional placeholders** for runtime substitution:
|
|
157
|
+
|
|
158
|
+
```xml
|
|
159
|
+
<labels>
|
|
160
|
+
<fullName>Save_Failed_Message</fullName>
|
|
161
|
+
<language>en_US</language>
|
|
162
|
+
<protected>false</protected>
|
|
163
|
+
<shortDescription>Error message when save fails</shortDescription>
|
|
164
|
+
<value>Failed to save {0}: {1}</value>
|
|
165
|
+
</labels>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
At call time:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
t("Save_Failed_Message", { 0: "Account", 1: "Permission denied" });
|
|
172
|
+
// → "Failed to save Account: Permission denied"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Translations must preserve the placeholders:**
|
|
176
|
+
|
|
177
|
+
```xml
|
|
178
|
+
<!-- es.translation-meta.xml -->
|
|
179
|
+
<customLabels>
|
|
180
|
+
<label>Error al guardar {0}: {1}</label>
|
|
181
|
+
<name>Save_Failed_Message</name>
|
|
182
|
+
</customLabels>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The placeholders can move (Spanish grammar might flip the order), but they must stay as `{0}`, `{1}`; i18next does the substitution at render time.
|
|
186
|
+
|
|
187
|
+
See [interpolation.md](interpolation.md) for how this works under the hood.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Deploy activation requirement
|
|
192
|
+
|
|
193
|
+
Before you can deploy a `<locale>.translation-meta.xml` file, the language must be **activated** in the org:
|
|
194
|
+
|
|
195
|
+
**Setup → Translation Workbench → Translation Settings → Add**
|
|
196
|
+
|
|
197
|
+
If you deploy a translation file for an inactive language, the deploy is rejected:
|
|
198
|
+
```text
|
|
199
|
+
Not available for deploy for this organization
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
English (`en_US`) needs no activation; it's always available.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Language vs Locale (a common confusion)
|
|
207
|
+
|
|
208
|
+
Salesforce has two separate settings:
|
|
209
|
+
- **Language** drives **translations**: the text the user sees (`en_US`, `en_GB`, `de`, `pt_BR`)
|
|
210
|
+
- **Locale** drives **formatting only**: dates, numbers, currency (`de_DE`, `fr_CA`)
|
|
211
|
+
|
|
212
|
+
A user can have Language = English, Locale = French: English text, French number formatting.
|
|
213
|
+
|
|
214
|
+
When you "add a language" for localization, you're working in the **Language** dimension. The SDK's i18n context exposes both: `lang` (Language) picks the translation, and `locale`/`currency` (Locale) feed `Intl` formatters.
|
|
215
|
+
|
|
216
|
+
To change a user's Language (to test translations), go to:
|
|
217
|
+
**Setup → My Settings → Language & Time Zone → Language** → pick the language → Save.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Example: full cycle for one label in two languages
|
|
222
|
+
|
|
223
|
+
### 1. Add the English base label
|
|
224
|
+
|
|
225
|
+
`force-app/main/default/labels/CustomLabels.labels-meta.xml`:
|
|
226
|
+
```xml
|
|
227
|
+
<labels>
|
|
228
|
+
<fullName>Welcome_Text</fullName>
|
|
229
|
+
<language>en_US</language>
|
|
230
|
+
<protected>false</protected>
|
|
231
|
+
<shortDescription>Welcome banner heading</shortDescription>
|
|
232
|
+
<value>Welcome</value>
|
|
233
|
+
</labels>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 2. Add the Spanish translation
|
|
237
|
+
|
|
238
|
+
`force-app/main/default/translations/es.translation-meta.xml`:
|
|
239
|
+
```xml
|
|
240
|
+
<customLabels>
|
|
241
|
+
<label>Bienvenido</label>
|
|
242
|
+
<name>Welcome_Text</name>
|
|
243
|
+
</customLabels>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### 3. Register in the manifest
|
|
247
|
+
|
|
248
|
+
`src/i18n/label-manifest.ts`:
|
|
249
|
+
```typescript
|
|
250
|
+
export const labelManifest = ["c:Welcome_Text"];
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### 4. Use in a component
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
import { useTranslation } from "react-i18next";
|
|
257
|
+
|
|
258
|
+
function WelcomeBanner() {
|
|
259
|
+
const { t } = useTranslation("c");
|
|
260
|
+
return <h1>{t("Welcome_Text")}</h1>;
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 5. Deploy
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
sf project deploy start --source-dir force-app --target-org <alias>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 6. Verify
|
|
271
|
+
|
|
272
|
+
- User with Language = English sees "Welcome"
|
|
273
|
+
- User with Language = Spanish sees "Bienvenido"
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Related
|
|
278
|
+
|
|
279
|
+
- [i18n-setup.md](i18n-setup.md): the init file + manifest wiring
|
|
280
|
+
- [interpolation.md](interpolation.md): how `{0}/{1}` substitution works
|
|
281
|
+
- [verifying.md](verifying.md): the serve/verify flow
|
|
282
|
+
- [gotchas.md](gotchas.md): silent-fail traps
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Verifying: serve, deploy, and test labels across locales
|
|
2
|
+
|
|
3
|
+
How to build, deploy, open, and verify that labels render correctly in multiple languages.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Verification has five steps:
|
|
10
|
+
1. **Build** the app (API version bakes in, point at the deploy target org first)
|
|
11
|
+
2. **Deploy** the bundle + labels + translations in one shot
|
|
12
|
+
3. **Open** the app at the correct URL (on the `lightning.force.com` domain)
|
|
13
|
+
4. **Flip** the user's Language setting to the translated language
|
|
14
|
+
5. **Reload** and confirm the labels render in the new language
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Step 1: Build the app
|
|
19
|
+
|
|
20
|
+
**Before building**, set the target org so the API version matches:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
sf config set target-org=<your-org-alias>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Why this matters:** The build plugin reads your **default org's** API version and stamps it into the bundle's JavaScript (`services/data/v{N}/graphql`). If you build while pointed at a v65.0 org and deploy to a v63.0 org, the bundle calls a GraphQL endpoint that org doesn't have, the call **404s, the i18n context fetch throws, and the app boots to a blank page** with no obvious error.
|
|
27
|
+
|
|
28
|
+
Then build:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm run build
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
(Run from the UI bundle directory, `force-app/main/default/uiBundles/<your-bundle>/`.)
|
|
35
|
+
|
|
36
|
+
The built output lands in `dist/` under the bundle directory. The deploy pushes the built JS, not your TypeScript source.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Step 2: Activate languages in the org (before deploy)
|
|
41
|
+
|
|
42
|
+
For every non-English language you're deploying, **activate it first** in the org:
|
|
43
|
+
|
|
44
|
+
**Setup → Translation Workbench → Translation Settings → Add**
|
|
45
|
+
|
|
46
|
+
Pick the languages (e.g., Spanish, French, German) and Save.
|
|
47
|
+
|
|
48
|
+
**Why:** Deploying a `<locale>.translation-meta.xml` for an inactive language fails with:
|
|
49
|
+
```text
|
|
50
|
+
Not available for deploy for this organization
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
English (`en_US`) needs no activation; it's always available.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Step 3: Deploy the bundle + labels + translations
|
|
58
|
+
|
|
59
|
+
Deploy the entire `force-app` tree (bundle, labels, translations) in one command:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
sf project deploy start --source-dir force-app --target-org <your-org-alias>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Run from the SFDX project root** (not from inside the bundle directory). `--source-dir force-app` deploys everything under that folder:
|
|
66
|
+
- `labels/CustomLabels.labels-meta.xml` (English base labels)
|
|
67
|
+
- `translations/<locale>.translation-meta.xml` (translated labels)
|
|
68
|
+
- `uiBundles/<your-bundle>/dist/` (the built app)
|
|
69
|
+
|
|
70
|
+
You do **not** need a `package.xml` or any manifest entry; the CLI discovers the metadata automatically.
|
|
71
|
+
|
|
72
|
+
**Point at `force-app`, not `uiBundles/`, or your labels and translations won't go up.**
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Step 4: Open the app
|
|
77
|
+
|
|
78
|
+
UI Bundles serve at a fixed LWR route:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
https://<your-org>.lightning.force.com/lwr/application/ai/<namespace>-<bundleName>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Parts:**
|
|
85
|
+
- `<your-org>`: your org's My Domain (e.g., `mycompany-dev-ed`)
|
|
86
|
+
- `<namespace>`: the bundle's namespace (usually `c` for custom)
|
|
87
|
+
- `<bundleName>`: the bundle's name (lowercased; the framework lowercases `appName` at lookup, so camelCase silently 404s)
|
|
88
|
+
|
|
89
|
+
**Example:** `https://mycompany-dev-ed.lightning.force.com/lwr/application/ai/c-freshi18n`
|
|
90
|
+
|
|
91
|
+
The `/lwr/application/ai/` segment is a fixed LWR route prefix; it's the same for every UI Bundle and isn't something you configure.
|
|
92
|
+
|
|
93
|
+
**Enhanced-domain orgs (scratch orgs are enhanced by default) redirect:** Type the `lightning.force.com` URL above, and the browser **redirects** to the standalone-app host:
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
https://<your-org>--<namespace>.<instance>.my.salesforce.app/lwr/application/ai/<namespace>-<bundleName>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
That's expected: a UI Bundle is a standalone **LWR** app, not part of Lightning Experience, so it serves from the `.my.salesforce.app` app host. The `lightning.force.com` URL is fine to type (it forwards); just don't be surprised when the address bar ends on `.my.salesforce.app`.
|
|
100
|
+
|
|
101
|
+
**If you see a blank page:**
|
|
102
|
+
- You're probably on the raw `my.salesforce.com` (API/session) host; switch to `lightning.force.com` and let it redirect.
|
|
103
|
+
- Or the API version is baked in wrong (built against a different org), see Step 1.
|
|
104
|
+
- Or the bundle name is camelCased in the URL (the framework lowercases it; use all lowercase).
|
|
105
|
+
|
|
106
|
+
See [gotchas.md](gotchas.md) for the full list of blank-page causes.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Step 5: Change the user's Language
|
|
111
|
+
|
|
112
|
+
To test translations, you need to change the **Language** setting (not Locale, see the note below).
|
|
113
|
+
|
|
114
|
+
**Setup → My Settings → Language & Time Zone → Language** → pick the language you translated (e.g., Spanish) → Save.
|
|
115
|
+
|
|
116
|
+
**Reload the app.** Labels should now render in the selected language.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Language vs Locale (common confusion)
|
|
121
|
+
|
|
122
|
+
Salesforce has two separate settings:
|
|
123
|
+
- **Language** drives **translations**: the text the user sees (`en_US`, `es`, `de`, `fr`)
|
|
124
|
+
- **Locale** drives **formatting only**: dates, numbers, currency (`en_US`, `de_DE`, `fr_CA`)
|
|
125
|
+
|
|
126
|
+
A user can have Language = English, Locale = French: English text, French number formatting.
|
|
127
|
+
|
|
128
|
+
When you test localization, **change the Language**, not the Locale. Changing Locale won't flip label text.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Troubleshooting: labels don't flip
|
|
133
|
+
|
|
134
|
+
### 1. Label shows in English when it should be translated
|
|
135
|
+
|
|
136
|
+
**Possible causes:**
|
|
137
|
+
- The language isn't activated (Step 2), though you'd have hit the deploy rejection if that were it.
|
|
138
|
+
- The translation file is missing that label, or its `<name>` doesn't match the `<fullName>` in `CustomLabels`.
|
|
139
|
+
- The user's **Language** isn't what you think; confirm it's set to the language you translated (not Locale).
|
|
140
|
+
|
|
141
|
+
**Check:** Go to Setup → Translation Workbench → Translate → pick the language and the label. Is the translation there? If not, author it and re-deploy.
|
|
142
|
+
|
|
143
|
+
**Fallback behavior:** If a key is in the manifest but untranslated for the active language, i18next renders the **English base value** (via `fallbackLng: "en"` in the init). That's correct behavior; it just means that one key wasn't translated yet.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
### 2. Label shows as its own key name
|
|
148
|
+
|
|
149
|
+
You see the literal string `Welcome_Text` on screen instead of "Welcome."
|
|
150
|
+
|
|
151
|
+
**Cause:** The key isn't in your `label-manifest.ts`. The app only fetches labels listed in the manifest, so an unregistered key is **never requested**, and i18next, finding nothing, renders the key string. **No console warning, no error**; it fails silently.
|
|
152
|
+
|
|
153
|
+
**Fix:** Add the `"c:Key"` entry to `label-manifest.ts` (Step 3 of the workflow). This is the most common localization bug; if a label looks wrong, check the manifest first.
|
|
154
|
+
|
|
155
|
+
See [gotchas.md](gotchas.md) for the full explanation.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### 3. You changed a translation but the app still shows the old text
|
|
160
|
+
|
|
161
|
+
You edited a label in the Translation Workbench (or redeployed a `translation-meta.xml`), confirmed the new value is in the org, but the app keeps rendering the **previous** value on reload.
|
|
162
|
+
|
|
163
|
+
**Cause:** The label cache. Your `src/i18n/index.ts` chains two backends, `[LocalStorageBackend, SalesforceBackend]`, so on load i18next reads labels from **localStorage first** and only falls through to GraphQL on a cache miss. Labels are cached per language+namespace under keys like `i18next_res_de-c` (DevTools → Application → Local Storage), with a 24-hour `expirationTime`. Until that entry expires, your app serves the cached copy and never refetches.
|
|
164
|
+
|
|
165
|
+
**Fix:** Clear the cached labels, then reload:
|
|
166
|
+
- **DevTools → Application → Local Storage** → delete the `i18next_res_*` keys
|
|
167
|
+
- Or **Clear site data** to wipe everything
|
|
168
|
+
|
|
169
|
+
The next load misses the cache, refetches over GraphQL, and shows the current value.
|
|
170
|
+
|
|
171
|
+
**This is expected behavior, not a bug.** The cache is what makes labels fast after first load. In production, a translation change takes up to `expirationTime` (24 hours) to roll out; during development, clear the cache to see edits immediately.
|
|
172
|
+
|
|
173
|
+
See [gotchas.md](gotchas.md) for the full explanation.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
### 4. A user on a regional Language (e.g., `en_GB`) sees English base text, not their locale's translation
|
|
178
|
+
|
|
179
|
+
This is expected, not a bug, **as long as you only authored the base (`en_US`) translation.**
|
|
180
|
+
|
|
181
|
+
Asked with `fallback: BASE_VALUE`, the GraphQL server returns the label's base value for a regional Language it has no explicit translation for: `resolvedLocale` comes back as the base (`en_US`) with `wasFallback: true`. The server does **not** map `en_GB → en_US` region-aware; it just honors the base-value fallback. On the documented SDK floor (11.42.1) the backend does not yet request `BASE_VALUE`, so it resolves with the server default (`USER_DEFAULT`): a guest or org-default user still lands on the base value, but see the related note below for the logged-in case. The base-value request ships in a later SDK release (see [gotchas.md](gotchas.md)).
|
|
182
|
+
|
|
183
|
+
**Fix (only if you want region-specific text):** Author a translation for that exact regional Language (`en_GB.translation-meta.xml`). Otherwise the base value is the intended, correct result.
|
|
184
|
+
|
|
185
|
+
**Related:** if instead a *logged-in* user sees **their own** language (not the org default) for an untranslated label, that's the fallback-strategy case, see [gotchas.md](gotchas.md) ("Logged-in user sees their own language instead of the org default"). On 11.42.1 that is the expected behavior, since the backend still uses `USER_DEFAULT`; author an explicit org-default translation to avoid it. The `BASE_VALUE` fallback that prevents it arrives in a later SDK release.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Verification checklist
|
|
190
|
+
|
|
191
|
+
Use this to confirm everything works:
|
|
192
|
+
|
|
193
|
+
- [ ] Built against the correct org (API version matches deploy target)
|
|
194
|
+
- [ ] Every translated language is activated in the org
|
|
195
|
+
- [ ] Deployed `force-app` (bundle + labels + translations in one shot)
|
|
196
|
+
- [ ] Opened at `lightning.force.com/lwr/application/ai/<namespace>-<bundleName>` (redirected to `.my.salesforce.app` is fine)
|
|
197
|
+
- [ ] Changed user's **Language** (not Locale) to the translated language
|
|
198
|
+
- [ ] Reloaded, labels render in the new language
|
|
199
|
+
- [ ] If labels are stale, cleared `i18next_res_*` from localStorage
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Quick reference: commands
|
|
204
|
+
|
|
205
|
+
| Command | Run from | Purpose |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| `sf config set target-org=<alias>` | Anywhere | Set default org (API version bakes in on next build) |
|
|
208
|
+
| `npm run build` | UI bundle dir | Build the app |
|
|
209
|
+
| `sf project deploy start --source-dir force-app --target-org <alias>` | Project root | Deploy bundle + labels + translations |
|
|
210
|
+
| `sf project retrieve start --metadata Translations:<locale>` | Project root | Pull translations authored in Translation Workbench |
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Related
|
|
215
|
+
|
|
216
|
+
- [i18n-setup.md](i18n-setup.md): the init file + manifest
|
|
217
|
+
- [label-xml.md](label-xml.md): Custom Labels + translations metadata
|
|
218
|
+
- [interpolation.md](interpolation.md): `{0}/{1}` placeholders
|
|
219
|
+
- [gotchas.md](gotchas.md): silent-fail traps (unregistered keys, stale cache, API-version mismatch)
|