Skip to content

Commit 783f105

Browse files
committed
localization; linting fixes
1 parent 95691fa commit 783f105

23 files changed

Lines changed: 571 additions & 123 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,5 @@ jobs:
4949
- name: Build packages
5050
run: pnpm -r run build
5151

52-
- name: Run tests
52+
- name: Run tests and lint
5353
run: pnpm -r run test
54-
55-
- name: Run linter
56-
run: pnpm -r run lint

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ package-lock.json
1414

1515
.claude/settings.local.json
1616
.envrc
17+
CLAUDE.md

packages/b2c-cli/eslint.config.mjs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,34 @@ import {fileURLToPath} from 'node:url'
66

77
const gitignorePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '.gitignore')
88

9-
export default [includeIgnoreFile(gitignorePath), ...oclif, prettier]
9+
export default [
10+
includeIgnoreFile(gitignorePath),
11+
...oclif,
12+
prettier,
13+
{
14+
rules: {
15+
// Disable perfectionist rules - we use prettier for formatting
16+
'perfectionist/sort-imports': 'off',
17+
'perfectionist/sort-objects': 'off',
18+
'perfectionist/sort-object-types': 'off',
19+
'perfectionist/sort-interfaces': 'off',
20+
'perfectionist/sort-named-exports': 'off',
21+
'perfectionist/sort-named-imports': 'off',
22+
// Disable stylistic rules that conflict with our style
23+
'@stylistic/lines-between-class-members': 'off',
24+
'@stylistic/padding-line-between-statements': 'off',
25+
// Allow TODO comments
26+
'no-warning-comments': 'off',
27+
// Don't require destructuring
28+
'prefer-destructuring': 'off',
29+
// Allow underscore-prefixed unused variables
30+
'@typescript-eslint/no-unused-vars': [
31+
'error',
32+
{
33+
argsIgnorePattern: '^_',
34+
varsIgnorePattern: '^_',
35+
},
36+
],
37+
},
38+
},
39+
]

packages/b2c-cli/src/commands/code/deploy.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Args } from '@oclif/core'
22
import { uploadCartridges } from '@salesforce/b2c-tooling'
33
import { InstanceCommand } from '@salesforce/b2c-tooling/cli'
4+
import { t } from '../../i18n/index.js'
45

56
export default class Deploy extends InstanceCommand<typeof Deploy> {
67
static args = {
@@ -10,7 +11,7 @@ export default class Deploy extends InstanceCommand<typeof Deploy> {
1011
}),
1112
}
1213

13-
static description = 'Deploy cartridges to a B2C Commerce instance'
14+
static description = t('commands.code.deploy.description', 'Deploy cartridges to a B2C Commerce instance')
1415

1516
static examples = [
1617
'<%= config.bin %> <%= command.id %>',
@@ -24,17 +25,20 @@ export default class Deploy extends InstanceCommand<typeof Deploy> {
2425
this.requireWebDavCredentials()
2526

2627
const instance = this.createWebDavInstance()
28+
const path = this.args.cartridgePath
29+
const hostname = this.resolvedConfig.hostname!
30+
const version = this.resolvedConfig.codeVersion!
2731

28-
this.log(`Deploying cartridges from ${this.args.cartridgePath}...`)
29-
this.log(`Target: ${this.resolvedConfig.hostname}`)
30-
this.log(`Code Version: ${this.resolvedConfig.codeVersion}`)
32+
this.log(t('commands.code.deploy.deploying', 'Deploying cartridges from {{path}}...', { path }))
33+
this.log(t('commands.code.deploy.target', 'Target: {{hostname}}', { hostname }))
34+
this.log(t('commands.code.deploy.codeVersion', 'Code Version: {{version}}', { version }))
3135

3236
try {
33-
await uploadCartridges(instance, this.args.cartridgePath)
34-
this.log('Deployment complete')
37+
await uploadCartridges(instance, path)
38+
this.log(t('commands.code.deploy.complete', 'Deployment complete'))
3539
} catch (error) {
3640
if (error instanceof Error) {
37-
this.error(`Deployment failed: ${error.message}`)
41+
this.error(t('commands.code.deploy.failed', 'Deployment failed: {{message}}', { message: error.message }))
3842
}
3943
throw error
4044
}

packages/b2c-cli/src/commands/mrt/env-var/set.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Args, Flags } from '@oclif/core'
22
import { MrtCommand } from '@salesforce/b2c-tooling/cli'
3+
import { t } from '../../../i18n/index.js'
34

45
/**
56
* Stub command demonstrating MrtCommand usage.
@@ -17,7 +18,7 @@ export default class MrtEnvVarSet extends MrtCommand<typeof MrtEnvVarSet> {
1718
}),
1819
}
1920

20-
static description = 'Set an environment variable on a Managed Runtime project'
21+
static description = t('commands.mrt.envVar.set.description', 'Set an environment variable on a Managed Runtime project')
2122

2223
static examples = [
2324
'<%= config.bin %> <%= command.id %> MY_VAR "my value" --project acme-storefront --environment production',
@@ -38,14 +39,19 @@ export default class MrtEnvVarSet extends MrtCommand<typeof MrtEnvVarSet> {
3839
async run(): Promise<void> {
3940
this.requireMrtCredentials()
4041

41-
this.log(`Setting ${this.args.key} on ${this.flags.project}/${this.flags.environment}...`)
42+
const key = this.args.key
43+
const value = this.args.value
44+
const project = this.flags.project
45+
const environment = this.flags.environment
46+
47+
this.log(t('commands.mrt.envVar.set.setting', 'Setting {{key}} on {{project}}/{{environment}}...', { key, project, environment }))
4248

4349
// TODO: Implement actual MRT API call using this.createMrtClient()
4450

4551
this.log('')
46-
this.log('(stub) Environment variable setting not yet implemented')
47-
this.log(`Would set ${this.args.key}=${this.args.value}`)
48-
this.log(`Project: ${this.flags.project}`)
49-
this.log(`Environment: ${this.flags.environment}`)
52+
this.log(t('commands.mrt.envVar.set.stub', '(stub) Environment variable setting not yet implemented'))
53+
this.log(t('commands.mrt.envVar.set.wouldSet', 'Would set {{key}}={{value}}', { key, value }))
54+
this.log(t('commands.mrt.envVar.set.project', 'Project: {{project}}', { project }))
55+
this.log(t('commands.mrt.envVar.set.environment', 'Environment: {{environment}}', { environment }))
5056
}
5157
}

packages/b2c-cli/src/commands/sandbox/create.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Args, Flags } from '@oclif/core'
22
import { OAuthCommand } from '@salesforce/b2c-tooling/cli'
3+
import { t } from '../../i18n/index.js'
34

45
/**
56
* Stub command demonstrating OAuthCommand usage.
@@ -13,7 +14,7 @@ export default class SandboxCreate extends OAuthCommand<typeof SandboxCreate> {
1314
}),
1415
}
1516

16-
static description = 'Create a new on-demand sandbox'
17+
static description = t('commands.sandbox.create.description', 'Create a new on-demand sandbox')
1718

1819
static examples = [
1920
'<%= config.bin %> <%= command.id %> abcd --ttl 24',
@@ -34,14 +35,19 @@ export default class SandboxCreate extends OAuthCommand<typeof SandboxCreate> {
3435
async run(): Promise<void> {
3536
this.requireOAuthCredentials()
3637

37-
this.log(`Creating sandbox in realm ${this.args.realm}...`)
38-
this.log(`Profile: ${this.flags.profile}`)
39-
this.log(`TTL: ${this.flags.ttl} hours`)
38+
const realm = this.args.realm
39+
const profile = this.flags.profile
40+
const ttl = this.flags.ttl
41+
const clientId = this.resolvedConfig.clientId
42+
43+
this.log(t('commands.sandbox.create.creating', 'Creating sandbox in realm {{realm}}...', { realm }))
44+
this.log(t('commands.sandbox.create.profile', 'Profile: {{profile}}', { profile }))
45+
this.log(t('commands.sandbox.create.ttl', 'TTL: {{ttl}} hours', { ttl }))
4046

4147
// TODO: Implement actual ODS API call using this.getOAuthStrategy()
4248

4349
this.log('')
44-
this.log('(stub) Sandbox creation not yet implemented')
45-
this.log(`Would create sandbox with OAuth client: ${this.resolvedConfig.clientId}`)
50+
this.log(t('commands.sandbox.create.stub', '(stub) Sandbox creation not yet implemented'))
51+
this.log(t('commands.sandbox.create.wouldCreate', 'Would create sandbox with OAuth client: {{clientId}}', { clientId }))
4652
}
4753
}

packages/b2c-cli/src/commands/sites/list.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { InstanceCommand } from '@salesforce/b2c-tooling/cli'
2+
import { t } from '../../i18n/index.js'
23

34
interface SitesResponse {
45
_v: string
@@ -12,7 +13,7 @@ interface SitesResponse {
1213
}
1314

1415
export default class SitesList extends InstanceCommand<typeof SitesList> {
15-
static description = 'List sites on a B2C Commerce instance'
16+
static description = t('commands.sites.list.description', 'List sites on a B2C Commerce instance')
1617

1718
static examples = [
1819
'<%= config.bin %> <%= command.id %>',
@@ -24,37 +25,46 @@ export default class SitesList extends InstanceCommand<typeof SitesList> {
2425
this.requireOAuthCredentials()
2526

2627
const instance = this.createApiInstance()
28+
const hostname = this.resolvedConfig.hostname!
2729

28-
this.log(`Fetching sites from ${this.resolvedConfig.hostname}...`)
30+
this.log(t('commands.sites.list.fetching', 'Fetching sites from {{hostname}}...', { hostname }))
2931

3032
try {
3133
const response = await instance.ocapiDataRequest('sites?select=(**)')
3234

3335
if (!response.ok) {
3436
const errorText = await response.text()
35-
this.error(`Failed to fetch sites: ${response.status} ${response.statusText}\n${errorText}`)
37+
this.error(
38+
t('commands.sites.list.fetchFailed', 'Failed to fetch sites: {{status}} {{statusText}}\n{{error}}', {
39+
status: response.status,
40+
statusText: response.statusText,
41+
error: errorText,
42+
})
43+
)
3644
}
3745

3846
const data = (await response.json()) as SitesResponse
3947

4048
if (data.count === 0) {
41-
this.log('No sites found.')
49+
this.log(t('commands.sites.list.noSites', 'No sites found.'))
4250
return
4351
}
4452

45-
this.log(`\nFound ${data.count} site(s):\n`)
53+
this.log('')
54+
this.log(t('commands.sites.list.foundSites', 'Found {{count}} site(s):', { count: data.count }))
55+
this.log('')
4656

4757
for (const site of data.data) {
4858
const displayName = site.display_name?.default || site.id
4959
const status = site.status || 'unknown'
5060
this.log(` ${site.id}`)
51-
this.log(` Display Name: ${displayName}`)
52-
this.log(` Status: ${status}`)
61+
this.log(` ${t('commands.sites.list.displayName', 'Display Name: {{name}}', { name: displayName })}`)
62+
this.log(` ${t('commands.sites.list.status', 'Status: {{status}}', { status })}`)
5363
this.log('')
5464
}
5565
} catch (error) {
5666
if (error instanceof Error) {
57-
this.error(`Failed to fetch sites: ${error.message}`)
67+
this.error(t('commands.sites.list.error', 'Failed to fetch sites: {{message}}', { message: error.message }))
5868
}
5969
throw error
6070
}

packages/b2c-cli/src/i18n/index.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* i18n setup for b2c-cli.
3+
*
4+
* This module registers CLI-specific translations with the 'cli' namespace.
5+
* The core i18n infrastructure comes from @salesforce/b2c-tooling.
6+
*
7+
* Usage in commands:
8+
* import { t } from '../i18n/index.js'
9+
* this.log(t('commands.sites.list.fetching', 'Fetching sites from {{hostname}}...', { hostname }))
10+
*/
11+
12+
import {registerTranslations, t as toolingT, TOptions} from '@salesforce/b2c-tooling'
13+
import {locales} from './locales/index.js'
14+
15+
/** The namespace used by b2c-cli messages */
16+
export const CLI_NAMESPACE = 'cli'
17+
18+
// Register all CLI translations
19+
for (const [lang, translations] of Object.entries(locales)) {
20+
registerTranslations(CLI_NAMESPACE, lang, translations)
21+
}
22+
23+
/**
24+
* Translate a CLI message key with an inline default.
25+
*
26+
* This is a convenience wrapper that uses the 'cli' namespace.
27+
* For b2c-tooling messages, import t directly from @salesforce/b2c-tooling.
28+
*
29+
* @param key - Dot-notation key (e.g., 'commands.sites.list.fetching')
30+
* @param defaultValue - The default English string
31+
* @param options - Optional interpolation values
32+
* @returns The translated string
33+
*
34+
* @example
35+
* t('commands.sites.list.fetching', 'Fetching sites from {{hostname}}...', { hostname })
36+
*/
37+
export function t(key: string, defaultValue: string, options?: TOptions): string {
38+
return toolingT(`${CLI_NAMESPACE}:${key}`, defaultValue, options)
39+
}
40+
41+
// Re-export for convenience
42+
export {setLanguage, getLanguage, getI18nInstance} from '@salesforce/b2c-tooling'
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* DE - German translations for b2c-cli commands.
3+
*/
4+
export const de = {
5+
commands: {
6+
sites: {
7+
list: {
8+
description: 'Sites auf einer B2C Commerce-Instanz auflisten',
9+
fetching: 'Rufe Sites von {{hostname}} ab...',
10+
fetchFailed: 'Sites konnten nicht abgerufen werden: {{status}} {{statusText}}\n{{error}}',
11+
noSites: 'Keine Sites gefunden.',
12+
foundSites: '{{count}} Site(s) gefunden:',
13+
displayName: 'Anzeigename: {{name}}',
14+
status: 'Status: {{status}}',
15+
error: 'Sites konnten nicht abgerufen werden: {{message}}',
16+
},
17+
},
18+
code: {
19+
deploy: {
20+
description: 'Cartridges auf eine B2C Commerce-Instanz deployen',
21+
deploying: 'Deploye Cartridges von {{path}}...',
22+
target: 'Ziel: {{hostname}}',
23+
codeVersion: 'Code-Version: {{version}}',
24+
complete: 'Deployment abgeschlossen',
25+
failed: 'Deployment fehlgeschlagen: {{message}}',
26+
},
27+
},
28+
sandbox: {
29+
create: {
30+
description: 'Eine neue On-Demand-Sandbox erstellen',
31+
creating: 'Erstelle Sandbox in Realm {{realm}}...',
32+
profile: 'Profil: {{profile}}',
33+
ttl: 'TTL: {{ttl}} Stunden',
34+
stub: '(stub) Sandbox-Erstellung noch nicht implementiert',
35+
wouldCreate: 'Würde Sandbox mit OAuth-Client erstellen: {{clientId}}',
36+
},
37+
},
38+
mrt: {
39+
envVar: {
40+
set: {
41+
description: 'Eine Umgebungsvariable für ein Managed Runtime-Projekt setzen',
42+
setting: 'Setze {{key}} auf {{project}}/{{environment}}...',
43+
stub: '(stub) Umgebungsvariablen-Einstellung noch nicht implementiert',
44+
wouldSet: 'Würde {{key}}={{value}} setzen',
45+
project: 'Projekt: {{project}}',
46+
environment: 'Umgebung: {{environment}}',
47+
},
48+
},
49+
},
50+
},
51+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* EN - English translations for b2c-cli commands.
3+
*
4+
* Note: These serve as documentation of translatable strings.
5+
* English defaults are also defined inline at point of use via t().
6+
*/
7+
export const en = {
8+
commands: {
9+
sites: {
10+
list: {
11+
description: 'List sites on a B2C Commerce instance',
12+
fetching: 'Fetching sites from {{hostname}}...',
13+
fetchFailed: 'Failed to fetch sites: {{status}} {{statusText}}\n{{error}}',
14+
noSites: 'No sites found.',
15+
foundSites: 'Found {{count}} site(s):',
16+
displayName: 'Display Name: {{name}}',
17+
status: 'Status: {{status}}',
18+
error: 'Failed to fetch sites: {{message}}',
19+
},
20+
},
21+
code: {
22+
deploy: {
23+
description: 'Deploy cartridges to a B2C Commerce instance',
24+
deploying: 'Deploying cartridges from {{path}}...',
25+
target: 'Target: {{hostname}}',
26+
codeVersion: 'Code Version: {{version}}',
27+
complete: 'Deployment complete',
28+
failed: 'Deployment failed: {{message}}',
29+
},
30+
},
31+
sandbox: {
32+
create: {
33+
description: 'Create a new on-demand sandbox',
34+
creating: 'Creating sandbox in realm {{realm}}...',
35+
profile: 'Profile: {{profile}}',
36+
ttl: 'TTL: {{ttl}} hours',
37+
stub: '(stub) Sandbox creation not yet implemented',
38+
wouldCreate: 'Would create sandbox with OAuth client: {{clientId}}',
39+
},
40+
},
41+
mrt: {
42+
envVar: {
43+
set: {
44+
description: 'Set an environment variable on a Managed Runtime project',
45+
setting: 'Setting {{key}} on {{project}}/{{environment}}...',
46+
stub: '(stub) Environment variable setting not yet implemented',
47+
wouldSet: 'Would set {{key}}={{value}}',
48+
project: 'Project: {{project}}',
49+
environment: 'Environment: {{environment}}',
50+
},
51+
},
52+
},
53+
},
54+
}

0 commit comments

Comments
 (0)