@pocket-trash/localizations 0.0.3
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/README.md +27 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +91 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @pocket-trash/localizations
|
|
2
|
+
|
|
3
|
+
Shared localization utilities and message catalogs for Pocket Trash.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @pocket-trash/localizations
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Use
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { formatMessage, resolveLocale } from '@pocket-trash/localizations';
|
|
15
|
+
|
|
16
|
+
const locale = resolveLocale('es-MX');
|
|
17
|
+
const label = formatMessage('action.save', {}, locale);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Develop
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
pnpm install
|
|
24
|
+
pnpm test
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Publishing notes live in [docs/publishing.md](docs/publishing.md).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { esMX } from '@clerk/localizations';
|
|
2
|
+
export type SupportedLocale = 'en' | 'es-MX';
|
|
3
|
+
export type MessageKey = 'app.name' | 'action.cancel' | 'action.save' | 'error.generic' | 'locale.current';
|
|
4
|
+
export type Messages = Readonly<Record<MessageKey, string>>;
|
|
5
|
+
export type LocalePreference = string | readonly string[] | null | undefined;
|
|
6
|
+
export type ClerkLocalizationResource = typeof esMX;
|
|
7
|
+
export declare const DEFAULT_LOCALE = "en";
|
|
8
|
+
export declare const SUPPORTED_LOCALES: readonly ["en", "es-MX"];
|
|
9
|
+
export declare const messages: Readonly<{
|
|
10
|
+
en: Readonly<{
|
|
11
|
+
'app.name': "Pocket Trash";
|
|
12
|
+
'action.cancel': "Cancel";
|
|
13
|
+
'action.save': "Save";
|
|
14
|
+
'error.generic': "Something went wrong.";
|
|
15
|
+
'locale.current': "Current language: {locale}";
|
|
16
|
+
}>;
|
|
17
|
+
'es-MX': Readonly<{
|
|
18
|
+
'app.name': "Pocket Trash";
|
|
19
|
+
'action.cancel': "Cancelar";
|
|
20
|
+
'action.save': "Guardar";
|
|
21
|
+
'error.generic': "Algo salio mal.";
|
|
22
|
+
'locale.current': "Idioma actual: {locale}";
|
|
23
|
+
}>;
|
|
24
|
+
}>;
|
|
25
|
+
export declare const messageKeys: readonly MessageKey[];
|
|
26
|
+
export declare const clerkLocalizations: Readonly<Record<SupportedLocale, ClerkLocalizationResource | undefined>>;
|
|
27
|
+
export declare function resolveLocale(...preferences: readonly LocalePreference[]): SupportedLocale;
|
|
28
|
+
export declare function getMessages(locale?: string | null): Messages;
|
|
29
|
+
export declare function getClerkLocalization(locale?: string | null): ClerkLocalizationResource | undefined;
|
|
30
|
+
export declare function formatMessage(key: MessageKey | string, values?: Readonly<Record<string, unknown>>, locale?: string | null): string;
|
|
31
|
+
export declare function assertCompleteCatalogs(): true;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { esMX } from '@clerk/localizations';
|
|
2
|
+
export const DEFAULT_LOCALE = 'en';
|
|
3
|
+
export const SUPPORTED_LOCALES = Object.freeze(['en', 'es-MX']);
|
|
4
|
+
const localeAliases = new Map([
|
|
5
|
+
['en', 'en'],
|
|
6
|
+
['en-us', 'en'],
|
|
7
|
+
['en-ca', 'en'],
|
|
8
|
+
['es', 'es-MX'],
|
|
9
|
+
['es-mx', 'es-MX'],
|
|
10
|
+
['es-us', 'es-MX'],
|
|
11
|
+
]);
|
|
12
|
+
export const messages = Object.freeze({
|
|
13
|
+
en: Object.freeze({
|
|
14
|
+
'app.name': 'Pocket Trash',
|
|
15
|
+
'action.cancel': 'Cancel',
|
|
16
|
+
'action.save': 'Save',
|
|
17
|
+
'error.generic': 'Something went wrong.',
|
|
18
|
+
'locale.current': 'Current language: {locale}',
|
|
19
|
+
}),
|
|
20
|
+
'es-MX': Object.freeze({
|
|
21
|
+
'app.name': 'Pocket Trash',
|
|
22
|
+
'action.cancel': 'Cancelar',
|
|
23
|
+
'action.save': 'Guardar',
|
|
24
|
+
'error.generic': 'Algo salio mal.',
|
|
25
|
+
'locale.current': 'Idioma actual: {locale}',
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
export const messageKeys = Object.freeze(Object.keys(messages[DEFAULT_LOCALE]));
|
|
29
|
+
export const clerkLocalizations = Object.freeze({
|
|
30
|
+
en: undefined,
|
|
31
|
+
'es-MX': esMX,
|
|
32
|
+
});
|
|
33
|
+
export function resolveLocale(...preferences) {
|
|
34
|
+
for (const preference of preferences.flat()) {
|
|
35
|
+
for (const tag of parseLocalePreference(preference)) {
|
|
36
|
+
const locale = matchLocale(tag);
|
|
37
|
+
if (locale)
|
|
38
|
+
return locale;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return DEFAULT_LOCALE;
|
|
42
|
+
}
|
|
43
|
+
export function getMessages(locale) {
|
|
44
|
+
return messages[resolveLocale(locale)];
|
|
45
|
+
}
|
|
46
|
+
export function getClerkLocalization(locale) {
|
|
47
|
+
return clerkLocalizations[resolveLocale(locale)];
|
|
48
|
+
}
|
|
49
|
+
export function formatMessage(key, values = {}, locale = DEFAULT_LOCALE) {
|
|
50
|
+
const template = getMessages(locale)[key] ?? messages[DEFAULT_LOCALE][key];
|
|
51
|
+
if (!template)
|
|
52
|
+
return key;
|
|
53
|
+
return template.replace(/\{([a-zA-Z0-9_]+)\}/g, (_, name) => values[name] == null ? `{${name}}` : String(values[name]));
|
|
54
|
+
}
|
|
55
|
+
export function assertCompleteCatalogs() {
|
|
56
|
+
const expected = new Set(messageKeys);
|
|
57
|
+
for (const [locale, catalog] of Object.entries(messages)) {
|
|
58
|
+
const keys = Object.keys(catalog);
|
|
59
|
+
const missing = messageKeys.filter((key) => !(key in catalog));
|
|
60
|
+
const extra = keys.filter((key) => !expected.has(key));
|
|
61
|
+
if (missing.length || extra.length) {
|
|
62
|
+
throw new Error(`${locale} catalog mismatch: missing ${missing.join(', ') || 'none'}; extra ${extra.join(', ') || 'none'}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
function parseLocalePreference(preference) {
|
|
68
|
+
if (typeof preference !== 'string' || !preference.trim())
|
|
69
|
+
return [];
|
|
70
|
+
if (!preference.includes(',') && !preference.includes(';'))
|
|
71
|
+
return [preference];
|
|
72
|
+
return preference
|
|
73
|
+
.split(',')
|
|
74
|
+
.map((part, index) => {
|
|
75
|
+
const [tag, ...params] = part.trim().split(';');
|
|
76
|
+
const q = params
|
|
77
|
+
.map((param) => param.trim().match(/^q=([0-9.]+)$/i)?.[1])
|
|
78
|
+
.find(Boolean);
|
|
79
|
+
return { tag, q: q == null ? 1 : Number(q), index };
|
|
80
|
+
})
|
|
81
|
+
.filter(({ tag, q }) => tag && Number.isFinite(q) && q > 0)
|
|
82
|
+
.sort((a, b) => b.q - a.q || a.index - b.index)
|
|
83
|
+
.map(({ tag }) => tag);
|
|
84
|
+
}
|
|
85
|
+
function matchLocale(tag) {
|
|
86
|
+
const normalized = tag.trim().replace('_', '-').toLowerCase();
|
|
87
|
+
if (normalized === '*')
|
|
88
|
+
return DEFAULT_LOCALE;
|
|
89
|
+
return localeAliases.get(normalized) ?? localeAliases.get(normalized.split('-')[0] ?? '') ?? null;
|
|
90
|
+
}
|
|
91
|
+
assertCompleteCatalogs();
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pocket-trash/localizations",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Shared localization utilities and message catalogs for Pocket Trash.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/Pocket-Trash/pocket-trash-localizations.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Pocket-Trash/pocket-trash-localizations/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/Pocket-Trash/pocket-trash-localizations#readme",
|
|
25
|
+
"keywords": [
|
|
26
|
+
"pocket-trash",
|
|
27
|
+
"localization",
|
|
28
|
+
"i18n"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.json",
|
|
36
|
+
"changeset": "changeset",
|
|
37
|
+
"changeset:version": "changeset version",
|
|
38
|
+
"release": "changeset publish",
|
|
39
|
+
"test": "pnpm run build && node --test"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@changesets/cli": "^2.31.1",
|
|
46
|
+
"typescript": "^5.9.2"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@clerk/localizations": "^4.14.2",
|
|
50
|
+
"lts": "^2.0.0"
|
|
51
|
+
},
|
|
52
|
+
"packageManager": "pnpm@11.10.0"
|
|
53
|
+
}
|