Initial commit
This commit is contained in:
62
packages/i18n/lib/consts.ts
Normal file
62
packages/i18n/lib/consts.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @url https://developer.chrome.com/docs/extensions/reference/api/i18n#support_multiple_languages
|
||||
*/
|
||||
export const SUPPORTED_LANGUAGES = {
|
||||
ar: 'Arabic',
|
||||
am: 'Amharic',
|
||||
bg: 'Bulgarian',
|
||||
bn: 'Bengali',
|
||||
ca: 'Catalan',
|
||||
cs: 'Czech',
|
||||
da: 'Danish',
|
||||
de: 'German',
|
||||
el: 'Greek',
|
||||
en: 'English',
|
||||
en_AU: 'English (Australia)',
|
||||
en_GB: 'English (Great Britain)',
|
||||
en_US: 'English (USA)',
|
||||
es: 'Spanish',
|
||||
es_419: 'Spanish (Latin America and Caribbean)',
|
||||
et: 'Estonian',
|
||||
fa: 'Persian',
|
||||
fi: 'Finnish',
|
||||
fil: 'Filipino',
|
||||
fr: 'French',
|
||||
gu: 'Gujarati',
|
||||
he: 'Hebrew',
|
||||
hi: 'Hindi',
|
||||
hr: 'Croatian',
|
||||
hu: 'Hungarian',
|
||||
id: 'Indonesian',
|
||||
it: 'Italian',
|
||||
ja: 'Japanese',
|
||||
kn: 'Kannada',
|
||||
ko: 'Korean',
|
||||
lt: 'Lithuanian',
|
||||
lv: 'Latvian',
|
||||
ml: 'Malayalam',
|
||||
mr: 'Marathi',
|
||||
ms: 'Malay',
|
||||
nl: 'Dutch',
|
||||
no: 'Norwegian',
|
||||
pl: 'Polish',
|
||||
pt_BR: 'Portuguese (Brazil)',
|
||||
pt_PT: 'Portuguese (Portugal)',
|
||||
ro: 'Romanian',
|
||||
ru: 'Russian',
|
||||
sk: 'Slovak',
|
||||
sl: 'Slovenian',
|
||||
sr: 'Serbian',
|
||||
sv: 'Swedish',
|
||||
sw: 'Swahili',
|
||||
ta: 'Tamil',
|
||||
te: 'Telugu',
|
||||
th: 'Thai',
|
||||
tr: 'Turkish',
|
||||
uk: 'Ukrainian',
|
||||
vi: 'Vietnamese',
|
||||
zh_CN: 'Chinese (China)',
|
||||
zh_TW: 'Chinese (Taiwan)',
|
||||
} as const;
|
||||
|
||||
export const I18N_FILE_PATH = './lib/i18n.ts';
|
||||
34
packages/i18n/lib/i18n-dev.ts
Normal file
34
packages/i18n/lib/i18n-dev.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
// IT WILL BE ADJUSTED TO YOUR LANGUAGE DURING BUILD TIME, DON'T MOVE BELOW IMPORT TO OTHER LINE
|
||||
import localeJSON from '../locales/en/messages.json' with { type: 'json' };
|
||||
import type { I18nValueType, LocalesJSONType } from './types.js';
|
||||
|
||||
const translate = (key: keyof LocalesJSONType, substitutions?: string | string[]) => {
|
||||
const localeValues = localeJSON[key] as I18nValueType;
|
||||
let message = localeValues.message;
|
||||
/**
|
||||
* This is a placeholder replacement logic. But it's not perfect.
|
||||
* It just imitates the behavior of the Chrome extension i18n API.
|
||||
* Please check the official document for more information And double-check the behavior on production build.
|
||||
*
|
||||
* @url https://developer.chrome.com/docs/extensions/how-to/ui/localization-message-formats#placeholders
|
||||
*/
|
||||
if (localeValues.placeholders) {
|
||||
Object.entries(localeValues.placeholders).forEach(([key, { content }]) => {
|
||||
if (content) {
|
||||
message = message.replace(new RegExp(`\\$${key}\\$`, 'gi'), content);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!substitutions) {
|
||||
return message;
|
||||
} else if (Array.isArray(substitutions)) {
|
||||
return substitutions.reduce((acc, cur, idx) => acc.replace(`$${idx++}`, cur), message);
|
||||
}
|
||||
|
||||
return message.replace(/\$(\d+)/, substitutions);
|
||||
};
|
||||
|
||||
const removePlaceholder = (message: string) => message.replace(/\$\d+/g, '');
|
||||
|
||||
export const t = (...args: Parameters<typeof translate>) => removePlaceholder(translate(...args));
|
||||
3
packages/i18n/lib/i18n-prod.ts
Normal file
3
packages/i18n/lib/i18n-prod.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import type { MessageKeyType } from './types.js';
|
||||
|
||||
export const t = (key: MessageKeyType, substitutions?: string | string[]) => chrome.i18n.getMessage(key, substitutions);
|
||||
4
packages/i18n/lib/index.ts
Normal file
4
packages/i18n/lib/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { t as t_dev_or_prod } from './i18n.js';
|
||||
import type { t as t_dev } from './i18n-dev.js';
|
||||
|
||||
export const t = t_dev_or_prod as unknown as typeof t_dev;
|
||||
22
packages/i18n/lib/prepare-build.ts
Normal file
22
packages/i18n/lib/prepare-build.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import setRelatedLocaleImports from './set-related-locale-import.js';
|
||||
import { IS_DEV } from '@extension/env';
|
||||
import { cpSync, existsSync, mkdirSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
(() => {
|
||||
const i18nPath = IS_DEV ? 'lib/i18n-dev.ts' : 'lib/i18n-prod.ts';
|
||||
cpSync(i18nPath, resolve('lib', 'i18n.ts'));
|
||||
|
||||
const outDir = resolve(import.meta.dirname, '..', '..', '..', '..', 'dist');
|
||||
if (!existsSync(outDir)) {
|
||||
mkdirSync(outDir);
|
||||
}
|
||||
|
||||
const localePath = resolve(outDir, '_locales');
|
||||
cpSync(resolve('locales'), localePath, { recursive: true });
|
||||
|
||||
if (IS_DEV) {
|
||||
setRelatedLocaleImports();
|
||||
}
|
||||
console.log('I18n build complete');
|
||||
})();
|
||||
38
packages/i18n/lib/set-related-locale-import.ts
Normal file
38
packages/i18n/lib/set-related-locale-import.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { I18N_FILE_PATH } from './consts.js';
|
||||
import { lstatSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import type { SupportedLanguagesKeysType, SupportedLanguagesWithoutRegionKeysType } from './types.js';
|
||||
|
||||
export default () => {
|
||||
const locale = Intl.DateTimeFormat().resolvedOptions().locale.replace('-', '_') as SupportedLanguagesKeysType;
|
||||
const localeWithoutRegion = locale.split('_')[0] as SupportedLanguagesWithoutRegionKeysType;
|
||||
|
||||
const localesDir = resolve(import.meta.dirname, '..', '..', 'locales');
|
||||
const readLocalesFolder = readdirSync(localesDir);
|
||||
|
||||
const implementedLocales = readLocalesFolder.map(innerDir => {
|
||||
if (lstatSync(resolve(localesDir, innerDir)).isDirectory()) {
|
||||
return innerDir;
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
const i18nFileSplitContent = readFileSync(I18N_FILE_PATH, 'utf-8').split('\n');
|
||||
|
||||
if (process.env['CEB_DEV_LOCALE']) {
|
||||
i18nFileSplitContent[1] = `import localeJSON from '../locales/${process.env['CEB_DEV_LOCALE']}/messages.json' with { type: 'json' };`;
|
||||
} else {
|
||||
if (implementedLocales.includes(locale)) {
|
||||
i18nFileSplitContent[1] = `import localeJSON from '../locales/${locale}/messages.json' with { type: 'json' };`;
|
||||
} else if (implementedLocales.includes(localeWithoutRegion)) {
|
||||
i18nFileSplitContent[1] = `import localeJSON from '../locales/${localeWithoutRegion}/messages.json' with { type: 'json' };`;
|
||||
} else {
|
||||
i18nFileSplitContent[1] = `import localeJSON from '../locales/en/messages.json' with { type: 'json' };`;
|
||||
}
|
||||
}
|
||||
|
||||
// Join lines back together
|
||||
const updatedI18nFile = i18nFileSplitContent.join('\n');
|
||||
|
||||
writeFileSync(I18N_FILE_PATH, updatedI18nFile, 'utf-8');
|
||||
};
|
||||
12
packages/i18n/lib/types.ts
Normal file
12
packages/i18n/lib/types.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import enMessage from '../locales/en/messages.json' with { type: 'json' };
|
||||
import type { SUPPORTED_LANGUAGES } from './consts.js';
|
||||
|
||||
export type SupportedLanguagesKeysType = keyof typeof SUPPORTED_LANGUAGES;
|
||||
export type SupportedLanguagesWithoutRegionKeysType = Exclude<SupportedLanguagesKeysType, `${string}_${string}`>;
|
||||
export type I18nValueType = {
|
||||
message: string;
|
||||
placeholders?: Record<string, { content?: string; example?: string }>;
|
||||
};
|
||||
|
||||
export type MessageKeyType = keyof typeof enMessage;
|
||||
export type LocalesJSONType = typeof enMessage;
|
||||
Reference in New Issue
Block a user