mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(packages): i18n (#1708)
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
import { mkdirSync, readdirSync, rmSync, unlinkSync, writeFileSync } from 'node:fs';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { LOCALES, localeAliases } from '../src/core/i18n/locales.ts';
|
||||
|
||||
const GENERATED_HEADER = '/** Generated by packages/core/scripts/generate-i18n-locales.ts — do not edit. */\n';
|
||||
|
||||
const coreRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const coreLocalesDir = resolve(coreRoot, 'src/core/i18n/locales');
|
||||
const htmlLocalesDir = resolve(coreRoot, '../html/src/i18n/locales');
|
||||
const reactLocalesDir = resolve(coreRoot, '../react/src/i18n/locales');
|
||||
|
||||
const localeTags = [...LOCALES, ...localeAliases(LOCALES)] as const;
|
||||
const PLATFORM_LOCALE_TAGS = ['en', ...localeTags] as const;
|
||||
|
||||
function importBinding(tag: string): string {
|
||||
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(tag) ? tag : tag.replace(/-/g, '_');
|
||||
}
|
||||
|
||||
function objectEntry(tag: string): string {
|
||||
const binding = importBinding(tag);
|
||||
if (tag === binding) {
|
||||
return ` ${tag},`;
|
||||
}
|
||||
return ` '${tag}': ${binding},`;
|
||||
}
|
||||
|
||||
function propertyKey(key: string): string {
|
||||
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : `'${key}'`;
|
||||
}
|
||||
|
||||
function generateLoadLocaleTs(): string {
|
||||
const entries = localeTags
|
||||
.map((tag) => ` ${propertyKey(tag.trim().replaceAll('_', '-').toLowerCase())}: () => import('./locales/${tag}'),`)
|
||||
.join('\n');
|
||||
|
||||
return `${GENERATED_HEADER}import { findLocaleKeys, getCanonicalLocaleKey, hasRegisteredLocale } from './registry';
|
||||
import type { Translations } from './types';
|
||||
|
||||
const loaders = {
|
||||
${entries}
|
||||
} as const satisfies Record<string, () => Promise<{ default: Partial<Translations> }>>;
|
||||
|
||||
/** Lazy-import a shipped locale pack when the tag is not already in the registry. */
|
||||
export async function loadLocale(tag: string): Promise<Partial<Translations> | undefined> {
|
||||
if (hasRegisteredLocale(tag)) return undefined;
|
||||
for (const chainTag of findLocaleKeys(tag)) {
|
||||
if (hasRegisteredLocale(chainTag)) return undefined;
|
||||
const load = loaders[getCanonicalLocaleKey(chainTag) as keyof typeof loaders];
|
||||
if (load) return (await load()).default;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
function generateCoreAllTs(): string {
|
||||
const importTags = ['en', ...localeTags].sort();
|
||||
const imports = importTags.map((tag) => `import ${importBinding(tag)} from './${tag}';`).join('\n');
|
||||
|
||||
const objectLines = [' en,', ...localeTags.map(objectEntry)].join('\n');
|
||||
|
||||
return `${GENERATED_HEADER}import type { Translations } from '../types';
|
||||
${imports}
|
||||
|
||||
/** Every built-in locale pack keyed by BCP 47 tag. */
|
||||
export const all = {
|
||||
${objectLines}
|
||||
} as const satisfies Record<string, Partial<Translations>>;
|
||||
|
||||
export type LocaleTag = keyof typeof all;
|
||||
|
||||
/** BCP 47 tags for every pack in {@link all}. */
|
||||
export const localeTags = Object.keys(all) as LocaleTag[];
|
||||
`;
|
||||
}
|
||||
|
||||
function generatePlatformDefaultReExport(tag: string): string {
|
||||
return `${GENERATED_HEADER}export { default } from '@videojs/core/i18n/locales/${tag}';
|
||||
`;
|
||||
}
|
||||
|
||||
function generatePlatformAllReExport(): string {
|
||||
return `${GENERATED_HEADER}export { all, type LocaleTag, localeTags } from '@videojs/core/i18n/locales/all';
|
||||
`;
|
||||
}
|
||||
|
||||
function generatePlatformRegisterTs(tag: string): string {
|
||||
return `${GENERATED_HEADER}import { registerI18n } from '@videojs/core/i18n';
|
||||
import translations from '@videojs/core/i18n/locales/${tag}';
|
||||
|
||||
registerI18n('${tag}', translations);
|
||||
`;
|
||||
}
|
||||
|
||||
function generatePlatformRegisterAllTs(): string {
|
||||
return `${GENERATED_HEADER}import { registerI18n } from '@videojs/core/i18n';
|
||||
import { all } from '@videojs/core/i18n/locales/all';
|
||||
|
||||
for (const [tag, translations] of Object.entries(all)) {
|
||||
registerI18n(tag, translations);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
function writeGenerated(path: string, content: string): void {
|
||||
writeFileSync(path, content.endsWith('\n') ? content : `${content}\n`);
|
||||
}
|
||||
|
||||
function syncPlatformLocaleDir(dir: string): void {
|
||||
const expected = new Set<string>([...PLATFORM_LOCALE_TAGS, 'all'].map((tag) => `${tag}.ts`));
|
||||
|
||||
for (const tag of PLATFORM_LOCALE_TAGS) {
|
||||
writeGenerated(resolve(dir, `${tag}.ts`), generatePlatformDefaultReExport(tag));
|
||||
const registerDir = resolve(dir, tag);
|
||||
mkdirSync(registerDir, { recursive: true });
|
||||
writeGenerated(resolve(registerDir, 'register.ts'), generatePlatformRegisterTs(tag));
|
||||
}
|
||||
|
||||
writeGenerated(resolve(dir, 'all.ts'), generatePlatformAllReExport());
|
||||
const allRegisterDir = resolve(dir, 'all');
|
||||
mkdirSync(allRegisterDir, { recursive: true });
|
||||
writeGenerated(resolve(allRegisterDir, 'register.ts'), generatePlatformRegisterAllTs());
|
||||
|
||||
for (const file of readdirSync(dir)) {
|
||||
if (!file.endsWith('.ts') || expected.has(file)) {
|
||||
continue;
|
||||
}
|
||||
unlinkSync(resolve(dir, file));
|
||||
}
|
||||
|
||||
const expectedDirs = new Set([...PLATFORM_LOCALE_TAGS, 'all']);
|
||||
for (const file of readdirSync(dir, { withFileTypes: true })) {
|
||||
if (!file.isDirectory() || expectedDirs.has(file.name)) {
|
||||
continue;
|
||||
}
|
||||
rmSync(resolve(dir, file.name), { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
writeGenerated(resolve(coreLocalesDir, 'all.ts'), generateCoreAllTs());
|
||||
writeGenerated(resolve(coreRoot, 'src/core/i18n/load-locale.ts'), generateLoadLocaleTs());
|
||||
syncPlatformLocaleDir(htmlLocalesDir);
|
||||
syncPlatformLocaleDir(reactLocalesDir);
|
||||
|
||||
console.log('[generate-i18n-locales] Updated core all.ts, load-locale.ts, and html/react locale re-exports');
|
||||
Reference in New Issue
Block a user