fix: Standardize locale codes and warn about unsupported ones (#1617)
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ChromeMessage } from '../build';
|
||||
import { applyChromeMessagePlaceholders, getSubstitutionCount } from '../utils';
|
||||
import {
|
||||
applyChromeMessagePlaceholders,
|
||||
getSubstitutionCount,
|
||||
standardizeLocale,
|
||||
} from '../utils';
|
||||
|
||||
describe('Utils', () => {
|
||||
describe('applyChromeMessagePlaceholders', () => {
|
||||
it('should return the combined stirng', () => {
|
||||
it('should return the combined string', () => {
|
||||
const input = {
|
||||
message: 'Hello $username$, welcome to $appName$',
|
||||
placeholders: {
|
||||
@@ -60,4 +64,30 @@ describe('Utils', () => {
|
||||
expect(getSubstitutionCount('Hello $10')).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('standardizeLocale', () => {
|
||||
it('should convert two-letter locale codes to lowercase', () => {
|
||||
expect(standardizeLocale('en')).toEqual('en');
|
||||
expect(standardizeLocale('EN')).toEqual('en');
|
||||
});
|
||||
|
||||
it('should convert locale code extensions to uppercase', () => {
|
||||
expect(standardizeLocale('en_US')).toEqual('en_US');
|
||||
expect(standardizeLocale('en_us')).toEqual('en_US');
|
||||
expect(standardizeLocale('es_419')).toEqual('es_419');
|
||||
});
|
||||
|
||||
it('should convert dashes to underscores', () => {
|
||||
expect(standardizeLocale('en_US')).toEqual('en_US');
|
||||
expect(standardizeLocale('en-US')).toEqual('en_US');
|
||||
});
|
||||
|
||||
it('should return the input string as-is for unknown formats', () => {
|
||||
expect(standardizeLocale('en_USSS')).toEqual('en_USSS');
|
||||
expect(standardizeLocale('en-')).toEqual('en-');
|
||||
expect(standardizeLocale('------')).toEqual('------');
|
||||
expect(standardizeLocale('test')).toEqual('test');
|
||||
expect(standardizeLocale('hello-world')).toEqual('hello-world');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,6 +10,8 @@ import { parseYAML, parseJSON5, parseTOML } from 'confbox';
|
||||
import { dirname, extname } from 'node:path';
|
||||
import { applyChromeMessagePlaceholders, getSubstitutionCount } from './utils';
|
||||
|
||||
export { SUPPORTED_LOCALES } from './supported-locales';
|
||||
|
||||
//
|
||||
// TYPES
|
||||
//
|
||||
|
||||
@@ -16,12 +16,14 @@ import {
|
||||
generateChromeMessagesText,
|
||||
parseMessagesFile,
|
||||
generateTypeText,
|
||||
SUPPORTED_LOCALES,
|
||||
} from './build';
|
||||
import glob from 'fast-glob';
|
||||
import { basename, extname, join, resolve } from 'node:path';
|
||||
import { watch } from 'chokidar';
|
||||
import { GeneratedPublicFile, WxtDirFileEntry } from 'wxt';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { standardizeLocale } from './utils';
|
||||
|
||||
export default defineWxtModule<I18nOptions>({
|
||||
name: '@wxt-dev/i18n',
|
||||
@@ -46,10 +48,22 @@ export default defineWxtModule<I18nOptions>({
|
||||
cwd: localesDir,
|
||||
absolute: true,
|
||||
});
|
||||
return files.map((file) => ({
|
||||
file,
|
||||
locale: basename(file).replace(extname(file), ''),
|
||||
}));
|
||||
|
||||
const unsupportedLocales: string[] = [];
|
||||
|
||||
const res = files.map((file) => {
|
||||
const rawLocale = basename(file).replace(extname(file), '');
|
||||
const locale = standardizeLocale(rawLocale);
|
||||
if (!SUPPORTED_LOCALES.has(locale)) unsupportedLocales.push(locale);
|
||||
return { file, locale };
|
||||
});
|
||||
|
||||
if (unsupportedLocales.length > 0)
|
||||
wxt.logger.warn(
|
||||
`Unsupported locales: [${unsupportedLocales.join(', ')}].\n\nWeb extensions only support a limited set of locales as described here: https://developer.chrome.com/docs/extensions/reference/api/i18n#locales`,
|
||||
);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
const generateOutputJsonFiles = async (): Promise<
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/** From https://developer.chrome.com/docs/extensions/reference/api/i18n#locales */
|
||||
export const SUPPORTED_LOCALES = new Set([
|
||||
'ar',
|
||||
'am',
|
||||
'bg',
|
||||
'bn',
|
||||
'ca',
|
||||
'cs',
|
||||
'da',
|
||||
'de',
|
||||
'el',
|
||||
'en',
|
||||
'en_AU',
|
||||
'en_GB',
|
||||
'en_US',
|
||||
'es',
|
||||
'es_419',
|
||||
'et',
|
||||
'fa',
|
||||
'fi',
|
||||
'fil',
|
||||
'fr',
|
||||
'gu',
|
||||
'he',
|
||||
'hi',
|
||||
'hr',
|
||||
'hu',
|
||||
'id',
|
||||
'it',
|
||||
'ja',
|
||||
'kn',
|
||||
'ko',
|
||||
'lt',
|
||||
'lv',
|
||||
'ml',
|
||||
'mr',
|
||||
'ms',
|
||||
'nl',
|
||||
'no',
|
||||
'pl',
|
||||
'pt_BR',
|
||||
'pt_PT',
|
||||
'ro',
|
||||
'ru',
|
||||
'sk',
|
||||
'sl',
|
||||
'sr',
|
||||
'sv',
|
||||
'sw',
|
||||
'ta',
|
||||
'te',
|
||||
'th',
|
||||
'tr',
|
||||
'uk',
|
||||
'vi',
|
||||
'zh_CN',
|
||||
'zh_TW',
|
||||
]);
|
||||
@@ -21,3 +21,16 @@ export function getSubstitutionCount(message: string): number {
|
||||
}
|
||||
|
||||
const MAX_SUBSTITUTIONS = 9;
|
||||
|
||||
/** Given a string, standardize it to the format `xx_YY`. */
|
||||
export function standardizeLocale(locale: string): string {
|
||||
if (locale.length === 2) return locale.toLowerCase();
|
||||
|
||||
const [is_match, prefix, suffix] =
|
||||
locale.match(/^([a-z]{2})[-_]([a-z]{2,3})$/i) ?? [];
|
||||
if (is_match) {
|
||||
return `${prefix.toLowerCase()}_${suffix.toUpperCase()}`;
|
||||
}
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user