addKey method

Future<CatalogRow> addKey({
  1. required String keyPath,
  2. required Map<String, dynamic> valuesByLocale,
  3. String? note,
  4. bool markGreenIfComplete = true,
})

Implementation

Future<CatalogRow> addKey({
  required String keyPath,
  required Map<String, dynamic> valuesByLocale,
  String? note,
  bool markGreenIfComplete = true,
}) async {
  if (!isValidCatalogKeyPath(keyPath)) {
    throw CatalogOperationException(
      'Invalid key path "$keyPath". Use dot-separated segments with letters, numbers, and underscores.',
    );
  }

  if (config.hideCatalogUiKeys) {
    final reserved = await _uiKeyResolver.resolve();
    if (reserved.contains(keyPath)) {
      throw CatalogOperationException('Key "$keyPath" is reserved by the catalog UI.');
    }
  }

  final dataset = await _repository.load();
  final locales = dataset.locales;
  if (locales.isEmpty) {
    throw CatalogOperationException(
      'No locale files found in ${config.resolveLangDirectory(projectRootPath)}.',
    );
  }

  for (final locale in locales) {
    if (catalogHasPath(dataset.translationsByLocale[locale] ?? const <String, dynamic>{}, keyPath)) {
      throw CatalogOperationException('Key "$keyPath" already exists in locale "$locale".');
    }
  }

  for (final locale in locales) {
    final localeMap = dataset.translationsByLocale.putIfAbsent(locale, () => <String, dynamic>{});
    final value = valuesByLocale.containsKey(locale) ? valuesByLocale[locale] : '';
    catalogSetValueByPath(localeMap, keyPath, value ?? '');
  }

  final state = await _stateStore.load(
    config: config,
    projectRootPath: projectRootPath,
  );

  final now = DateTime.now().toUtc();
  final sourceValue = valuesByLocale[config.effectiveSourceLocale] ?? '';
  final sourceHash = _statusEngine.hashSourceValue(sourceValue);
  state.keys[keyPath] = _statusEngine.newKeyState(
    locales: locales,
    sourceLocale: config.effectiveSourceLocale,
    sourceHash: sourceHash,
    valuesByLocale: valuesByLocale,
    markGreenIfComplete: markGreenIfComplete,
    now: now,
  )..note = _normalizeCatalogNote(note);
  _appendActivityEvent(
    keyState: state.keys[keyPath]!,
    event: CatalogActivityEvent(
      kind: CatalogActivityKinds.keyCreated,
      timestamp: now,
    ),
  );

  _mergeDataTypesIntoDataset(dataset, state, locales);
  await _repository.save(dataset);
  await _stateStore.save(
    config: config,
    projectRootPath: projectRootPath,
    state: state,
  );

  _triggerDictionaryGeneration();
  return _buildRowForKey(
    keyPath: keyPath,
    locales: locales,
    translationsByLocale: dataset.translationsByLocale,
    state: state,
    now: now,
  );
}