angular-t9n
Version:
A translation tool for Angular i18n
127 lines (112 loc) • 4.24 kB
text/typescript
import { normalize, Path, relative, workspaces } from '@angular-devkit/core';
import {
TargetPathBuilder,
TranslationSource,
TranslationTarget,
TranslationTargetRegistry,
} from '../../../server';
import { AngularJsonI18n, AngularJsonI18nLocale } from './angular-json-i18n';
export class AngularI18n {
constructor(
private _host: workspaces.WorkspaceHost,
private _workspaceRoot: Path,
private _projectName: string,
private _targetPathBuilder: TargetPathBuilder,
private _translationContextFactory: () => {
source: TranslationSource;
targetRegistry: TranslationTargetRegistry;
},
) {}
async sourceLocale(): Promise<{ code: string; baseHref?: string }> {
const i18n = await this._readProjectI18n();
return typeof i18n.sourceLocale === 'object'
? i18n.sourceLocale
: { code: i18n.sourceLocale || '' };
}
async locales(): Promise<{ [locale: string]: { translation: string[]; baseHref?: string } }> {
const i18n = await this._readProjectI18n();
const locales = i18n.locales || {};
return Object.keys(locales)
.sort()
.reduce(
(current, next) =>
Object.assign(current, {
[next]: this._normalizeI18nLocale(locales[next]),
}),
{} as { [locale: string]: { translation: string[]; baseHref?: string } },
);
}
async update(): Promise<void> {
const { source, targetRegistry } = this._translationContextFactory();
const i18n = await this._readProjectI18n();
if (typeof i18n.sourceLocale === 'object' || source.baseHref) {
i18n.sourceLocale = {
code: source.language,
baseHref:
source.baseHref ||
(typeof i18n.sourceLocale === 'object'
? i18n.sourceLocale.baseHref
: `/${source.language}/`),
};
} else {
i18n.sourceLocale = source.language;
}
const locales = i18n.locales ?? {};
i18n.locales = targetRegistry
.values()
.sort((a, b) => a.language.localeCompare(b.language))
.reduce(
(current, next) =>
Object.assign(current, {
[next.language]: this._i18nLocale(next, locales[next.language]),
}),
{},
);
const { project, workspace } = await this._readProject();
// Cheap deep equal comparison
if (JSON.stringify(project.extensions.i18n) !== JSON.stringify(i18n)) {
project.extensions.i18n = i18n as any;
await workspaces.writeWorkspace(workspace, this._host);
}
}
projectRelativePath(target: TranslationTarget) {
return relative(this._workspaceRoot, normalize(this._targetPathBuilder.createPath(target)));
}
private async _readProjectI18n(): Promise<AngularJsonI18n> {
const { project } = await this._readProject();
return (project.extensions.i18n as any) || {};
}
private async _readProject() {
const { workspace } = await workspaces.readWorkspace(this._workspaceRoot, this._host);
const project = workspace.projects.get(this._projectName)!;
return { workspace, project };
}
private _i18nLocale(target: TranslationTarget, locale: AngularJsonI18nLocale | undefined) {
const translationPath = this.projectRelativePath(target);
const normalizedLocale = locale ? this._normalizeI18nLocale(locale) : { translation: [] };
if (!normalizedLocale.translation.includes(translationPath)) {
normalizedLocale.translation.push(translationPath);
}
const translation =
normalizedLocale.translation.length === 1
? normalizedLocale.translation[0]
: normalizedLocale.translation;
return target.baseHref && target.baseHref !== target.language
? { translation, baseHref: target.baseHref }
: translation;
}
private _normalizeI18nLocale(locale: AngularJsonI18nLocale): {
translation: string[];
baseHref?: string;
} {
if (typeof locale === 'string') {
return { translation: [locale] };
} else if (Array.isArray(locale)) {
return { translation: locale };
} else if (!Array.isArray(locale.translation)) {
return { ...locale, translation: [locale.translation] };
} else {
return locale as { translation: string[]; baseHref?: string };
}
}
}