@salesforce/vscode-i18n 65.5.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.txt +27 -0
- package/README.md +120 -0
- package/out/src/constants.d.ts +5 -0
- package/out/src/constants.d.ts.map +1 -0
- package/out/src/constants.js +13 -0
- package/out/src/i18n/advancedLocalization.d.ts +37 -0
- package/out/src/i18n/advancedLocalization.d.ts.map +1 -0
- package/out/src/i18n/advancedLocalization.js +149 -0
- package/out/src/i18n/localization.d.ts +8 -0
- package/out/src/i18n/localization.d.ts.map +1 -0
- package/out/src/i18n/localization.js +21 -0
- package/out/src/i18n/message.d.ts +10 -0
- package/out/src/i18n/message.d.ts.map +1 -0
- package/out/src/i18n/message.js +62 -0
- package/out/src/index.d.ts +11 -0
- package/out/src/index.d.ts.map +1 -0
- package/out/src/index.js +24 -0
- package/out/src/types/localization/advancedTypes.d.ts +7 -0
- package/out/src/types/localization/advancedTypes.d.ts.map +1 -0
- package/out/src/types/localization/advancedTypes.js +9 -0
- package/out/src/types/localization/config.d.ts +5 -0
- package/out/src/types/localization/config.d.ts.map +1 -0
- package/out/src/types/localization/config.js +9 -0
- package/out/src/types/localization/localizationProvider.d.ts +4 -0
- package/out/src/types/localization/localizationProvider.d.ts.map +1 -0
- package/out/src/types/localization/localizationProvider.js +9 -0
- package/out/src/types/localization/messageArgs.d.ts +5 -0
- package/out/src/types/localization/messageArgs.d.ts.map +1 -0
- package/out/src/types/localization/messageArgs.js +9 -0
- package/out/src/types/localization/messageBundle.d.ts +4 -0
- package/out/src/types/localization/messageBundle.d.ts.map +1 -0
- package/out/src/types/localization/messageBundle.js +3 -0
- package/out/test/jest/i18n/advancedLocalization.test.d.ts +2 -0
- package/out/test/jest/i18n/advancedLocalization.test.d.ts.map +1 -0
- package/out/test/jest/i18n/advancedLocalization.test.js +340 -0
- package/out/test/jest/i18n/localization.test.d.ts +2 -0
- package/out/test/jest/i18n/localization.test.d.ts.map +1 -0
- package/out/test/jest/i18n/localization.test.js +32 -0
- package/out/test/jest/i18n/message.test.d.ts +2 -0
- package/out/test/jest/i18n/message.test.d.ts.map +1 -0
- package/out/test/jest/i18n/message.test.js +153 -0
- package/out/test/jest/types/localization.test.d.ts +2 -0
- package/out/test/jest/types/localization.test.d.ts.map +1 -0
- package/out/test/jest/types/localization.test.js +132 -0
- package/package.json +33 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright (c) 2025, Salesforce.com, inc.
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
5
|
+
are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice, this
|
|
11
|
+
list of conditions and the following disclaimer in the documentation and/or
|
|
12
|
+
other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
* Neither the name of Salesforce.com nor the names of its contributors may be
|
|
15
|
+
used to endorse or promote products derived from this software without specific
|
|
16
|
+
prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
19
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
20
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
22
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
23
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
24
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
25
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
27
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# @salesforce/vscode-i18n
|
|
2
|
+
|
|
3
|
+
Internationalization (i18n) library for Salesforce VS Code extensions.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides a comprehensive type-safe localization system for VS Code extensions, with automatic type inference for message arguments based on printf-style format specifiers.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @salesforce/vscode-i18n
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Type-safe message localization**: Compile-time validation of message arguments
|
|
18
|
+
- **Multiple locale support**: Built-in support for English (en) and Japanese (ja)
|
|
19
|
+
- **Format specifier support**: Full support for Node.js `util.format()` specifiers (`%s`, `%d`, `%i`, `%f`, `%j`, `%%`)
|
|
20
|
+
- **Message bundle management**: Advanced localization service for managing multiple message bundles
|
|
21
|
+
- **Zero runtime cost**: Type safety with no performance impact
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Basic Usage
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { LocalizationService, MessageArgs } from '@salesforce/vscode-i18n';
|
|
29
|
+
|
|
30
|
+
// Define your message bundles
|
|
31
|
+
const enMessages = {
|
|
32
|
+
greeting: 'Hello %s',
|
|
33
|
+
userStats: 'User %s has %d points'
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
const jaMessages = {
|
|
37
|
+
greeting: 'こんにちは %s',
|
|
38
|
+
userStats: 'ユーザー %s は %d ポイントを持っています'
|
|
39
|
+
} as const;
|
|
40
|
+
|
|
41
|
+
// Create a localization service instance
|
|
42
|
+
const service = LocalizationService.getInstance('my-extension');
|
|
43
|
+
|
|
44
|
+
// Register message bundles
|
|
45
|
+
service.messageBundleManager.registerMessageBundle('my-extension', {
|
|
46
|
+
messages: enMessages,
|
|
47
|
+
type: 'base'
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
service.messageBundleManager.registerMessageBundle('my-extension', {
|
|
51
|
+
messages: { ...jaMessages, _locale: 'ja' },
|
|
52
|
+
type: 'locale',
|
|
53
|
+
locale: 'ja'
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Use type-safe localization
|
|
57
|
+
type MessageKey = keyof typeof enMessages;
|
|
58
|
+
const nls = {
|
|
59
|
+
localize: <K extends MessageKey>(key: K, ...args: MessageArgs<K, typeof enMessages>): string =>
|
|
60
|
+
service.localize(key, ...args)
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Type-safe calls with IntelliSense support
|
|
64
|
+
nls.localize('greeting', 'World'); // ✅ string
|
|
65
|
+
nls.localize('userStats', 'John', 150); // ✅ string, number
|
|
66
|
+
// nls.localize('greeting', 123); // ❌ Error: Expected string
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Type Safety
|
|
70
|
+
|
|
71
|
+
The package includes `MessageArgs` type that automatically infers argument types from format specifiers:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { MessageArgs } from '@salesforce/vscode-i18n';
|
|
75
|
+
|
|
76
|
+
const messages = {
|
|
77
|
+
simple: 'Task %s completed',
|
|
78
|
+
complex: 'User %s has %d points and data %j'
|
|
79
|
+
} as const;
|
|
80
|
+
|
|
81
|
+
type SimpleArgs = MessageArgs<'simple', typeof messages>; // [string]
|
|
82
|
+
type ComplexArgs = MessageArgs<'complex', typeof messages>; // [string, number, any]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## API
|
|
86
|
+
|
|
87
|
+
### LocalizationService
|
|
88
|
+
|
|
89
|
+
Singleton service for managing message bundles and localization.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const service = LocalizationService.getInstance(instanceName: string);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### MessageBundleManager
|
|
96
|
+
|
|
97
|
+
Manages message bundles for different locales.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
service.messageBundleManager.registerMessageBundle(instanceName, {
|
|
101
|
+
messages: messageBundle,
|
|
102
|
+
type: 'base' | 'locale',
|
|
103
|
+
locale?: Locale
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Constants
|
|
108
|
+
|
|
109
|
+
- `DEFAULT_LOCALE`: The default locale ('en')
|
|
110
|
+
- `LOCALE_JA`: Japanese locale constant ('ja')
|
|
111
|
+
- `MISSING_LABEL_MSG`: Error message for missing labels
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
BSD-3-Clause
|
|
116
|
+
|
|
117
|
+
## Support
|
|
118
|
+
|
|
119
|
+
For issues or questions, please file an issue at:
|
|
120
|
+
https://github.com/forcedotcom/salesforcedx-vscode/issues
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAErD,eAAO,MAAM,cAAc,EAAE,MAAa,CAAC;AAC3C,eAAO,MAAM,SAAS,EAAE,MAAa,CAAC;AACtC,eAAO,MAAM,iBAAiB,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2022, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.MISSING_LABEL_MSG = exports.LOCALE_JA = exports.DEFAULT_LOCALE = void 0;
|
|
10
|
+
exports.DEFAULT_LOCALE = 'en';
|
|
11
|
+
exports.LOCALE_JA = 'ja';
|
|
12
|
+
exports.MISSING_LABEL_MSG = '!!! MISSING LABEL !!!';
|
|
13
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AdvancedMessageBundle } from '../types/localization/advancedTypes';
|
|
2
|
+
import { Config, Locale } from '../types/localization/config';
|
|
3
|
+
import { Localization } from './localization';
|
|
4
|
+
import { Message } from './message';
|
|
5
|
+
/** export only for test */
|
|
6
|
+
export declare class LocalizationConfig {
|
|
7
|
+
private static instance;
|
|
8
|
+
private constructor();
|
|
9
|
+
static getInstance(): LocalizationConfig;
|
|
10
|
+
isLocaleSupported(locale: unknown): boolean;
|
|
11
|
+
getDefaultLocale(): Locale;
|
|
12
|
+
}
|
|
13
|
+
/** exported only for test */
|
|
14
|
+
export declare class MessageBundleManager {
|
|
15
|
+
private static instances;
|
|
16
|
+
private baseMessages;
|
|
17
|
+
private localeMessages;
|
|
18
|
+
private messageBundles;
|
|
19
|
+
private constructor();
|
|
20
|
+
static getInstance(instanceName: string): MessageBundleManager;
|
|
21
|
+
registerMessageBundle(instanceName: string, bundle: AdvancedMessageBundle): void;
|
|
22
|
+
private rebuildMessages;
|
|
23
|
+
private isValidLocale;
|
|
24
|
+
loadMessageBundle(config?: Config): Message;
|
|
25
|
+
}
|
|
26
|
+
export declare class LocalizationService {
|
|
27
|
+
static instances: Map<string, LocalizationService>;
|
|
28
|
+
private _nls;
|
|
29
|
+
readonly messageBundleManager: MessageBundleManager;
|
|
30
|
+
private readonly instanceName;
|
|
31
|
+
private constructor();
|
|
32
|
+
static getInstance(instanceName: string): LocalizationService;
|
|
33
|
+
get nls(): Localization;
|
|
34
|
+
localize<K extends string>(key: K, ...args: any[]): string;
|
|
35
|
+
refreshLocalization(): void;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=advancedLocalization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advancedLocalization.d.ts","sourceRoot":"","sources":["../../../src/i18n/advancedLocalization.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,2BAA2B;AAC3B,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAiC;IAExD,OAAO;WAEO,WAAW,IAAI,kBAAkB;IAKxC,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;IAI3C,gBAAgB,IAAI,MAAM;CAGlC;AAED,6BAA6B;AAC7B,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAC,SAAS,CAA2C;IACnE,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,cAAc,CAA8C;IAEpE,OAAO;WAEO,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,oBAAoB;IAU9D,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI;IAgBvF,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,aAAa;IAOd,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO;CAenD;AAED,qBAAa,mBAAmB;IAC9B,OAAc,SAAS,mCAA0C;IACjE,OAAO,CAAC,IAAI,CAA6B;IACzC,SAAgB,oBAAoB,EAAE,oBAAoB,CAAC;IAC3D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IAEtC,OAAO;WAKO,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,mBAAmB;IAUpE,IAAW,GAAG,IAAI,YAAY,CAc7B;IAEM,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM;IAK1D,mBAAmB,IAAI,IAAI;CAGnC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2024, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.LocalizationService = exports.MessageBundleManager = exports.LocalizationConfig = void 0;
|
|
10
|
+
const constants_1 = require("../constants");
|
|
11
|
+
const localization_1 = require("./localization");
|
|
12
|
+
const message_1 = require("./message");
|
|
13
|
+
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
|
14
|
+
const SUPPORTED_LOCALES = [constants_1.DEFAULT_LOCALE, constants_1.LOCALE_JA];
|
|
15
|
+
/**
|
|
16
|
+
* Type guard function to check if a value is a valid Locale
|
|
17
|
+
* @param value - The value to check
|
|
18
|
+
* @returns true if the value is a valid Locale, false otherwise
|
|
19
|
+
*/
|
|
20
|
+
const isLocale = (value) => {
|
|
21
|
+
if (typeof value !== 'string') {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return SUPPORTED_LOCALES.includes(value);
|
|
25
|
+
};
|
|
26
|
+
/** export only for test */
|
|
27
|
+
class LocalizationConfig {
|
|
28
|
+
static instance;
|
|
29
|
+
constructor() { }
|
|
30
|
+
static getInstance() {
|
|
31
|
+
LocalizationConfig.instance ??= new LocalizationConfig();
|
|
32
|
+
return LocalizationConfig.instance;
|
|
33
|
+
}
|
|
34
|
+
isLocaleSupported(locale) {
|
|
35
|
+
return isLocale(locale);
|
|
36
|
+
}
|
|
37
|
+
getDefaultLocale() {
|
|
38
|
+
return constants_1.DEFAULT_LOCALE;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.LocalizationConfig = LocalizationConfig;
|
|
42
|
+
/** exported only for test */
|
|
43
|
+
class MessageBundleManager {
|
|
44
|
+
static instances = new Map();
|
|
45
|
+
baseMessages = null;
|
|
46
|
+
localeMessages = new Map();
|
|
47
|
+
messageBundles = new Map();
|
|
48
|
+
constructor() { }
|
|
49
|
+
static getInstance(instanceName) {
|
|
50
|
+
const instance = MessageBundleManager.instances.get(instanceName);
|
|
51
|
+
if (!instance) {
|
|
52
|
+
const newInstance = new MessageBundleManager();
|
|
53
|
+
MessageBundleManager.instances.set(instanceName, newInstance);
|
|
54
|
+
return newInstance;
|
|
55
|
+
}
|
|
56
|
+
return instance;
|
|
57
|
+
}
|
|
58
|
+
registerMessageBundle(instanceName, bundle) {
|
|
59
|
+
if (!this.messageBundles.has(instanceName)) {
|
|
60
|
+
this.messageBundles.set(instanceName, []);
|
|
61
|
+
}
|
|
62
|
+
const bundles = this.messageBundles.get(instanceName);
|
|
63
|
+
if (bundles) {
|
|
64
|
+
bundles.push(bundle);
|
|
65
|
+
this.rebuildMessages(instanceName);
|
|
66
|
+
// Refresh any LocalizationService instances that might be using this bundle manager
|
|
67
|
+
const localizationService = LocalizationService.instances.get(instanceName);
|
|
68
|
+
if (localizationService) {
|
|
69
|
+
localizationService.refreshLocalization();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
rebuildMessages(instanceName) {
|
|
74
|
+
const bundles = this.messageBundles.get(instanceName) ?? [];
|
|
75
|
+
const baseBundle = bundles.find(b => b.type === 'base');
|
|
76
|
+
const localeBundles = bundles.filter(b => b.type === 'locale');
|
|
77
|
+
if (baseBundle) {
|
|
78
|
+
this.baseMessages = new message_1.Message(baseBundle.messages);
|
|
79
|
+
localeBundles.forEach(localeBundle => {
|
|
80
|
+
const messageLocale = localeBundle.messages['_locale'];
|
|
81
|
+
const locale = localeBundle.locale ?? (this.isValidLocale(messageLocale) ? messageLocale : constants_1.DEFAULT_LOCALE);
|
|
82
|
+
if (this.isValidLocale(locale)) {
|
|
83
|
+
this.localeMessages.set(locale, new message_1.Message(localeBundle.messages, this.baseMessages));
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
isValidLocale(locale) {
|
|
89
|
+
if (typeof locale !== 'string') {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return SUPPORTED_LOCALES.includes(locale);
|
|
93
|
+
}
|
|
94
|
+
loadMessageBundle(config) {
|
|
95
|
+
if (!this.baseMessages) {
|
|
96
|
+
throw new Error('No base messages registered');
|
|
97
|
+
}
|
|
98
|
+
const localeConfig = config?.locale ?? constants_1.DEFAULT_LOCALE;
|
|
99
|
+
const configManager = LocalizationConfig.getInstance();
|
|
100
|
+
if (!configManager.isLocaleSupported(localeConfig)) {
|
|
101
|
+
console.error(`Cannot find ${localeConfig}, defaulting to ${constants_1.DEFAULT_LOCALE}`);
|
|
102
|
+
return this.baseMessages;
|
|
103
|
+
}
|
|
104
|
+
return this.localeMessages.get(localeConfig) ?? this.baseMessages;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.MessageBundleManager = MessageBundleManager;
|
|
108
|
+
class LocalizationService {
|
|
109
|
+
static instances = new Map();
|
|
110
|
+
_nls = null;
|
|
111
|
+
messageBundleManager;
|
|
112
|
+
instanceName;
|
|
113
|
+
constructor(instanceName) {
|
|
114
|
+
this.instanceName = instanceName;
|
|
115
|
+
this.messageBundleManager = MessageBundleManager.getInstance(instanceName);
|
|
116
|
+
}
|
|
117
|
+
static getInstance(instanceName) {
|
|
118
|
+
const instance = LocalizationService.instances.get(instanceName);
|
|
119
|
+
if (!instance) {
|
|
120
|
+
const newInstance = new LocalizationService(instanceName);
|
|
121
|
+
LocalizationService.instances.set(instanceName, newInstance);
|
|
122
|
+
return newInstance;
|
|
123
|
+
}
|
|
124
|
+
return instance;
|
|
125
|
+
}
|
|
126
|
+
get nls() {
|
|
127
|
+
if (!this._nls) {
|
|
128
|
+
try {
|
|
129
|
+
const message = this.messageBundleManager.loadMessageBundle();
|
|
130
|
+
this._nls = new localization_1.Localization(message);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
console.warn(`LocalizationService: No messages registered for instance '${this.instanceName}', using fallback localization`);
|
|
134
|
+
const emptyMessage = new message_1.Message({});
|
|
135
|
+
this._nls = new localization_1.Localization(emptyMessage);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return this._nls;
|
|
139
|
+
}
|
|
140
|
+
localize(key, ...args) {
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
142
|
+
return this.nls.localize(key, ...args);
|
|
143
|
+
}
|
|
144
|
+
refreshLocalization() {
|
|
145
|
+
this._nls = null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.LocalizationService = LocalizationService;
|
|
149
|
+
//# sourceMappingURL=advancedLocalization.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { LocalizationProvider } from '../types/localization/localizationProvider';
|
|
2
|
+
import { Message } from './message';
|
|
3
|
+
export declare class Localization implements LocalizationProvider {
|
|
4
|
+
private readonly delegate;
|
|
5
|
+
constructor(delegate: Message);
|
|
6
|
+
localize(label: string, ...args: any[]): string;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=localization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localization.d.ts","sourceRoot":"","sources":["../../../src/i18n/localization.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAClF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,qBAAa,YAAa,YAAW,oBAAoB;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;gBAEvB,QAAQ,EAAE,OAAO;IAItB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM;CAIvD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2022, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.Localization = void 0;
|
|
10
|
+
class Localization {
|
|
11
|
+
delegate;
|
|
12
|
+
constructor(delegate) {
|
|
13
|
+
this.delegate = delegate;
|
|
14
|
+
}
|
|
15
|
+
localize(label, ...args) {
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
17
|
+
return this.delegate.localize(label, ...args);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.Localization = Localization;
|
|
21
|
+
//# sourceMappingURL=localization.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { LocalizationProvider } from '../types/localization/localizationProvider';
|
|
2
|
+
import { MessageBundle } from '../types/localization/messageBundle';
|
|
3
|
+
export declare class Message implements LocalizationProvider {
|
|
4
|
+
private readonly delegate?;
|
|
5
|
+
private readonly messages;
|
|
6
|
+
constructor(messages: MessageBundle, delegate?: Message);
|
|
7
|
+
localize(label: string, ...args: any[]): string;
|
|
8
|
+
private getLabel;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/i18n/message.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEpE,qBAAa,OAAQ,YAAW,oBAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAE7B,QAAQ,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,OAAO;IAKhD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM;IAmCtD,OAAO,CAAC,QAAQ;CASjB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Message = void 0;
|
|
4
|
+
/*
|
|
5
|
+
* Copyright (c) 2022, salesforce.com, inc.
|
|
6
|
+
* All rights reserved.
|
|
7
|
+
* Licensed under the BSD 3-Clause license.
|
|
8
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
9
|
+
*/
|
|
10
|
+
const node_util_1 = require("node:util");
|
|
11
|
+
const constants_1 = require("../constants");
|
|
12
|
+
class Message {
|
|
13
|
+
delegate;
|
|
14
|
+
messages;
|
|
15
|
+
constructor(messages, delegate) {
|
|
16
|
+
this.messages = messages;
|
|
17
|
+
this.delegate = delegate;
|
|
18
|
+
}
|
|
19
|
+
localize(label, ...args) {
|
|
20
|
+
let possibleLabel = this.getLabel(label);
|
|
21
|
+
if (!possibleLabel) {
|
|
22
|
+
console.warn(`Missing label for key: ${label}`);
|
|
23
|
+
possibleLabel = `${constants_1.MISSING_LABEL_MSG} ${label}`;
|
|
24
|
+
if (args.length > 0) {
|
|
25
|
+
args.forEach(arg => {
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
27
|
+
possibleLabel += ` (${arg})`;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return possibleLabel;
|
|
31
|
+
}
|
|
32
|
+
let labelArgs = args;
|
|
33
|
+
if (args.length > 0) {
|
|
34
|
+
// Count all printf-style format specifiers: %s, %d, %i, %f, %j, %%, etc.
|
|
35
|
+
const formatSpecifiers = possibleLabel.match(/%[sdifj%]/g);
|
|
36
|
+
const expectedNumArgs = formatSpecifiers ? formatSpecifiers.filter(spec => spec !== '%%').length : 0;
|
|
37
|
+
if (args.length !== expectedNumArgs) {
|
|
38
|
+
// just log it, we might want to hide some in some languages on purpose
|
|
39
|
+
console.log(`Arguments do not match for label '${label}', got ${args.length} but want ${expectedNumArgs}`);
|
|
40
|
+
// remove the extra args
|
|
41
|
+
if (args.length > expectedNumArgs) {
|
|
42
|
+
labelArgs = args.slice(0, -(args.length - expectedNumArgs));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return (0, node_util_1.format)(possibleLabel, ...labelArgs);
|
|
46
|
+
}
|
|
47
|
+
return possibleLabel;
|
|
48
|
+
}
|
|
49
|
+
getLabel(label) {
|
|
50
|
+
if (this.messages[label]) {
|
|
51
|
+
return this.messages[label];
|
|
52
|
+
}
|
|
53
|
+
else if (this.delegate) {
|
|
54
|
+
return this.delegate.messages[label];
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.Message = Message;
|
|
62
|
+
//# sourceMappingURL=message.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { Locale } from './types/localization/config';
|
|
2
|
+
export { MessageArgs } from './types/localization/messageArgs';
|
|
3
|
+
export { MessageBundle } from './types/localization/messageBundle';
|
|
4
|
+
export { AdvancedMessageBundle } from './types/localization/advancedTypes';
|
|
5
|
+
export { LocalizationProvider } from './types/localization/localizationProvider';
|
|
6
|
+
export { Config } from './types/localization/config';
|
|
7
|
+
export { LocalizationService, LocalizationConfig, MessageBundleManager } from './i18n/advancedLocalization';
|
|
8
|
+
export { Localization } from './i18n/localization';
|
|
9
|
+
export { Message } from './i18n/message';
|
|
10
|
+
export { DEFAULT_LOCALE, LOCALE_JA, MISSING_LABEL_MSG } from './constants';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAGrD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC5G,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAGzC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|
package/out/src/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2024, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.MISSING_LABEL_MSG = exports.LOCALE_JA = exports.DEFAULT_LOCALE = exports.Message = exports.Localization = exports.MessageBundleManager = exports.LocalizationConfig = exports.LocalizationService = void 0;
|
|
10
|
+
// i18n
|
|
11
|
+
var advancedLocalization_1 = require("./i18n/advancedLocalization");
|
|
12
|
+
Object.defineProperty(exports, "LocalizationService", { enumerable: true, get: function () { return advancedLocalization_1.LocalizationService; } });
|
|
13
|
+
Object.defineProperty(exports, "LocalizationConfig", { enumerable: true, get: function () { return advancedLocalization_1.LocalizationConfig; } });
|
|
14
|
+
Object.defineProperty(exports, "MessageBundleManager", { enumerable: true, get: function () { return advancedLocalization_1.MessageBundleManager; } });
|
|
15
|
+
var localization_1 = require("./i18n/localization");
|
|
16
|
+
Object.defineProperty(exports, "Localization", { enumerable: true, get: function () { return localization_1.Localization; } });
|
|
17
|
+
var message_1 = require("./i18n/message");
|
|
18
|
+
Object.defineProperty(exports, "Message", { enumerable: true, get: function () { return message_1.Message; } });
|
|
19
|
+
// Constants
|
|
20
|
+
var constants_1 = require("./constants");
|
|
21
|
+
Object.defineProperty(exports, "DEFAULT_LOCALE", { enumerable: true, get: function () { return constants_1.DEFAULT_LOCALE; } });
|
|
22
|
+
Object.defineProperty(exports, "LOCALE_JA", { enumerable: true, get: function () { return constants_1.LOCALE_JA; } });
|
|
23
|
+
Object.defineProperty(exports, "MISSING_LABEL_MSG", { enumerable: true, get: function () { return constants_1.MISSING_LABEL_MSG; } });
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advancedTypes.d.ts","sourceRoot":"","sources":["../../../../src/types/localization/advancedTypes.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
//# sourceMappingURL=advancedTypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/types/localization/config.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AAEjC,MAAM,MAAM,MAAM,GAAG;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2024, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localizationProvider.d.ts","sourceRoot":"","sources":["../../../../src/types/localization/localizationProvider.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC;CAC5D,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2024, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
//# sourceMappingURL=localizationProvider.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type PlaceholderToType<S extends string> = S extends '%s' ? string : S extends '%d' ? number : S extends '%i' ? number : S extends '%f' ? number : S extends '%j' ? any : unknown;
|
|
2
|
+
type ExtractArgs<S extends string, Acc extends any[] = []> = S extends `${infer _}%${infer P}${infer Rest}` ? P extends 's' | 'd' | 'i' | 'f' | 'j' ? ExtractArgs<Rest, [...Acc, PlaceholderToType<`%${P}`>]> : ExtractArgs<Rest, Acc> : Acc;
|
|
3
|
+
export type MessageArgs<K extends keyof T, T extends Record<string, string>> = ExtractArgs<T[K]>;
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=messageArgs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messageArgs.d.ts","sourceRoot":"","sources":["../../../../src/types/localization/messageArgs.ts"],"names":[],"mappings":"AAQA,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,IAAI,GACrD,MAAM,GACN,CAAC,SAAS,IAAI,GACZ,MAAM,GACN,CAAC,SAAS,IAAI,GACZ,MAAM,GACN,CAAC,SAAS,IAAI,GACZ,MAAM,GACN,CAAC,SAAS,IAAI,GACZ,GAAG,GACH,OAAO,CAAC;AAIpB,KAAK,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,IAAI,EAAE,GACvG,CAAC,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GACnC,WAAW,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,EAAE,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GACvD,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,GACxB,GAAG,CAAC;AAGR,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2025, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
//# sourceMappingURL=messageArgs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messageBundle.d.ts","sourceRoot":"","sources":["../../../../src/types/localization/messageBundle.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advancedLocalization.test.d.ts","sourceRoot":"","sources":["../../../../test/jest/i18n/advancedLocalization.test.ts"],"names":[],"mappings":""}
|