updateCell method

Future<CatalogRow> updateCell({
  1. required String keyPath,
  2. required String locale,
  3. required dynamic value,
})

Implementation

Future<CatalogRow> updateCell({
  required String keyPath,
  required String locale,
  required dynamic value,
}) async {
  final loaded = await _loadAndSyncState();
  if (!loaded.locales.contains(locale)) {
    throw CatalogOperationException('Locale "$locale" is not configured.');
  }
  if (!loaded.keyPaths.contains(keyPath)) {
    throw CatalogOperationException('Key "$keyPath" does not exist.');
  }

  final localeMap = loaded.dataset.translationsByLocale[locale]!;
  final previousValue = catalogGetValueByPath(localeMap, keyPath);
  catalogSetValueByPath(localeMap, keyPath, value);

  final now = DateTime.now().toUtc();
  final sourceLocale = config.effectiveSourceLocale;
  final sourceMap = loaded.dataset.translationsByLocale[sourceLocale] ?? const <String, dynamic>{};
  final sourceValue = catalogGetValueByPath(sourceMap, keyPath);

  final keyState = loaded.state.keys.putIfAbsent(
    keyPath,
    () => CatalogKeyState(sourceHash: '', cells: <String, CatalogCellState>{}),
  );

  if (locale == sourceLocale) {
    keyState.sourceHash = _statusEngine.hashSourceValue(sourceValue);
    keyState.cells[sourceLocale] = _statusEngine.markGreen(
      current: keyState.cells[sourceLocale],
      sourceHash: keyState.sourceHash,
      now: now,
    );
    for (final targetLocale in loaded.locales) {
      if (targetLocale == sourceLocale) {
        continue;
      }
      final targetValue = catalogGetValueByPath(
        loaded.dataset.translationsByLocale[targetLocale] ?? const <String, dynamic>{},
        keyPath,
      );
      keyState.cells[targetLocale] = isCatalogValueEmpty(targetValue)
          ? _statusEngine.markRed(
              current: keyState.cells[targetLocale],
              reason: CatalogStatusReasons.targetMissing,
              now: now,
            )
          : _statusEngine.markWarning(
              current: keyState.cells[targetLocale],
              reason: CatalogStatusReasons.sourceChanged,
              now: now,
            );
    }
    if (_catalogValueSignature(previousValue) != _catalogValueSignature(value)) {
      _appendActivityEvent(
        keyState: keyState,
        event: CatalogActivityEvent(
          kind: CatalogActivityKinds.sourceUpdated,
          timestamp: now,
          locale: sourceLocale,
        ),
      );
    }
  } else {
    if (isCatalogValueEmpty(value)) {
      keyState.cells[locale] = _statusEngine.markRed(
        current: keyState.cells[locale],
        reason: CatalogStatusReasons.targetMissing,
        now: now,
      );
    } else {
      keyState.cells[locale] = _statusEngine.markWarning(
        current: keyState.cells[locale],
        reason: CatalogStatusReasons.targetUpdatedNeedsReview,
        now: now,
      );
    }
    if (_catalogValueSignature(previousValue) != _catalogValueSignature(value)) {
      _appendActivityEvent(
        keyState: keyState,
        event: CatalogActivityEvent(
          kind: CatalogActivityKinds.targetUpdated,
          timestamp: now,
          locale: locale,
        ),
      );
    }
  }

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

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