UNPKG

@jsverse/transloco

Version:

The internationalization (i18n) library for Angular

181 lines 9.07 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ngAdd = ngAdd; const node_path_1 = require("node:path"); const schematics_1 = require("@angular-devkit/schematics"); const ng_ast_utils_1 = require("@schematics/angular/utility/ng-ast-utils"); const util_1 = require("@schematics/angular/utility/standalone/util"); const rules_1 = require("@schematics/angular/utility/standalone/rules"); const app_config_1 = require("@schematics/angular/utility/standalone/app_config"); const schematics_core_1 = require("../../schematics-core"); const schema_1 = require("./schema"); const http_loader_gen_1 = require("./generators/http-loader.gen"); const root_module_gen_1 = require("./generators/root-module.gen"); function updateEnvironmentBaseUrl(host, sourceRoot, defaultValue) { const template = `$1{ baseUrl: '${defaultValue}',`; (0, schematics_core_1.setEnvironments)(host, sourceRoot, (env) => env.indexOf('baseUrl') === -1 ? env.replace(/(environment.*=*)\{/, template) : env); } function resolveLoaderPath({ host, mainPath, isStandalone, modulePath, }) { var _a; let resolved = modulePath; if (isStandalone) { const bootstrapCall = (0, util_1.findBootstrapApplicationCall)(host, mainPath); resolved = ((_a = (0, app_config_1.findAppConfig)(bootstrapCall, host, mainPath)) === null || _a === void 0 ? void 0 : _a.filePath) || mainPath; resolved = (0, node_path_1.dirname)(resolved); } return resolved; } /** * Checks whether a directory "exists" in the schematic Tree. * * In the Angular DevKit schematic virtual file system, directories are *not real entities* — * only files exist. A directory is considered to "exist" if it has at least one file or * subdirectory (that itself contains files) under its path. * * This function returns `true` if the given directory path contains any files or subdirectories, * and `false` otherwise (including for empty or nonexistent directories). * * @param tree - The schematic virtual file system (Tree) * @param dirPath - The path to check, e.g. '/src' or '/public' */ function dirExists(tree, dirPath) { const dir = tree.getDir(dirPath); return dir.subfiles.length > 0 || dir.subdirs.length > 0; } /** * Detects the appropriate path for translation assets based on Angular project structure. * * Angular 18+ introduced a new project structure using a top-level `public/` directory instead * of `src/assets/` for static assets. This function implements a three-tier detection strategy * to determine where translation JSON files should be placed: * * 1. **Directory existence check**: If `/public` exists, assume Angular 18+ structure * 2. **Legacy assets check**: If `${sourceRoot}/assets` exists, use traditional structure * 3. **Version fallback**: Parse package.json @angular/core version as final determination * * The detection accounts for the fact that in schematics, we're working with a virtual file * system where directories only "exist" if they contain files, and we need to make the right * choice for where users expect their translation files to be placed. * * @param host - The schematic virtual file system (Tree) * @param sourceRoot - The source root path (typically 'src' or 'projects/app-name/src') * @returns The detected assets path, e.g. 'public/i18n/' or 'src/assets/i18n/' */ function detectAssetsPath(host, sourceRoot) { var _a, _b; if (dirExists(host, '/public')) { return 'public/i18n/'; } if (dirExists(host, `${sourceRoot}/assets`)) { return `${sourceRoot}/assets/i18n/`; } // Fallback: Check package.json for Angular version try { const packageJson = JSON.parse(host.read('/package.json').toString()); const version = ((_a = packageJson.dependencies) === null || _a === void 0 ? void 0 : _a['@angular/core']) || ((_b = packageJson.devDependencies) === null || _b === void 0 ? void 0 : _b['@angular/core']); // Extract major version number from versions like "^18.2.0", "~17.0.0", ">=16.0.0", etc. const majorVersionMatch = version === null || version === void 0 ? void 0 : version.match(/(\d+)\./); const majorVersion = parseInt(majorVersionMatch[1]); return majorVersion >= 18 ? 'public/i18n/' : `${sourceRoot}/assets/i18n/`; } catch (_c) { return `${sourceRoot}/assets/i18n/`; // Safe default } } function getUrlPathFromAssetsPath(assetsPath) { if (assetsPath.startsWith('public/')) { return assetsPath.replace('public/', ''); } return assetsPath; } function ngAdd(options) { return (host, context) => __awaiter(this, void 0, void 0, function* () { var _a; const langs = options.langs.split(',').map((l) => l.trim()); if (!options.project) { throw new schematics_1.SchematicsException('Project name is required. You must explicitly provide the project name using --project=<project-name>'); } const project = (0, schematics_core_1.getProject)(host, options.project); const sourceRoot = (_a = project.sourceRoot) !== null && _a !== void 0 ? _a : 'src'; const isLib = project.projectType === 'library'; const assetsPath = options.path ? `${sourceRoot}/${options.path}` : detectAssetsPath(host, sourceRoot); const urlPath = getUrlPathFromAssetsPath(assetsPath); const mainPath = yield (0, util_1.getMainFilePath)(host, options.project); const isStandalone = (0, ng_ast_utils_1.isStandaloneApp)(host, mainPath); const modulePath = isStandalone ? '' : (0, node_path_1.dirname)((0, ng_ast_utils_1.getAppModulePath)(host, mainPath)); const actions = []; if (options.loader === schema_1.Loaders.Http) { const loaderPath = resolveLoaderPath({ host, mainPath, isStandalone, modulePath, }); if (isStandalone) { actions.push((0, rules_1.addRootProvider)(options.project, ({ code, external }) => code `${external('provideHttpClient', '@angular/common/http')}()`)); } else { actions.push((0, rules_1.addRootImport)(options.project, ({ code, external }) => code `${external('HttpClientModule', '@angular/common/http')}`)); } actions.push((0, schematics_1.mergeWith)((0, http_loader_gen_1.createLoaderFile)({ ssr: options.ssr, loaderPath, urlPath, }))); } const hasTranslationFiles = (0, schematics_core_1.checkIfTranslationFilesExist)(assetsPath, langs, '.json', true); if (!hasTranslationFiles) { actions.push((0, schematics_1.mergeWith)((0, schematics_core_1.createTranslateFiles)(langs, assetsPath))); } if (isStandalone) { actions.push((0, rules_1.addRootProvider)(options.project, ({ code, external }) => { external('isDevMode', '@angular/core'); external('TranslocoHttpLoader', './transloco-loader'); return code `${external('provideTransloco', '@jsverse/transloco')}({ config: { availableLangs: [${(0, schematics_core_1.stringifyList)(langs)}], defaultLang: '${langs[0]}', // Remove this option if your application doesn't support changing language in runtime. reRenderOnLangChange: true, prodMode: !isDevMode(), }, loader: TranslocoHttpLoader })`; })); } else { actions.push((0, rules_1.addRootImport)(options.project, ({ code, external }) => code `${external('TranslocoRootModule', './transloco-root.module')}`), (0, schematics_1.mergeWith)((0, root_module_gen_1.createTranslocoModule)({ sourceRoot, isLib, ssr: options.ssr, langs, modulePath, host, }))); } if (options.ssr) { updateEnvironmentBaseUrl(host, sourceRoot, 'http://localhost:4200'); } (0, schematics_core_1.createGlobalConfig)(host, langs, assetsPath); return (0, schematics_1.chain)(actions)(host, context); }); } //# sourceMappingURL=index.js.map