*/ public static function degrees(): array { return [ 'associate' => ['zh-CN' => '大专', 'en' => 'Associate Degree'], 'bachelor' => ['zh-CN' => '本科', 'en' => "Bachelor’s Degree"], 'master' => ['zh-CN' => '硕士', 'en' => "Master’s Degree"], 'doctorate' => ['zh-CN' => '博士', 'en' => 'Doctorate'], 'other' => ['zh-CN' => '其他', 'en' => 'Other'], ]; } /** * @return array */ public static function locationCountries(): array { return [ 'cn' => ['zh-CN' => '中国', 'en' => 'China'], 'overseas' => ['zh-CN' => '海外', 'en' => 'Outside China'], ]; } /** * @return array */ public static function eventLocations(): array { return [ 'shanghai' => ['zh-CN' => '上海', 'en' => 'Shanghai'], 'suzhou' => ['zh-CN' => '苏州', 'en' => 'Suzhou'], 'shenzhen' => ['zh-CN' => '深圳', 'en' => 'Shenzhen'], ]; } /** * @return array */ public static function audiencePurposes(): array { return [ 'networking' => ['zh-CN' => '项目交流', 'en' => 'Project Networking'], 'collaboration' => ['zh-CN' => '产业合作', 'en' => 'Industry Collaboration'], 'investment' => ['zh-CN' => '投资对接', 'en' => 'Investor Meetings'], 'study' => ['zh-CN' => '学习参访', 'en' => 'Study Visit'], 'media' => ['zh-CN' => '媒体报道', 'en' => 'Media Coverage'], 'other' => ['zh-CN' => '其他', 'en' => 'Other'], ]; } /** * @return array */ public static function legacyMap(string $kind): array { return match ($kind) { 'degree' => [ '大专' => 'associate', '本科' => 'bachelor', '硕士' => 'master', '博士' => 'doctorate', '其他' => 'other', ], 'location_country' => [ '中国' => 'cn', '海外' => 'overseas', ], 'event_location' => [ '上海' => 'shanghai', '苏州' => 'suzhou', '深圳' => 'shenzhen', '上海赛区' => 'shanghai', '苏州赛区' => 'suzhou', '深圳赛区' => 'shenzhen', 'Shanghai' => 'shanghai', 'Suzhou' => 'suzhou', 'Shenzhen' => 'shenzhen', ], 'purpose', 'audience_purpose' => [ '项目交流' => 'networking', '产业合作' => 'collaboration', '投资对接' => 'investment', '学习参访' => 'study', '媒体报道' => 'media', '其他' => 'other', ], default => [], }; } public static function normalize(string $kind, ?string $raw): ?string { if ($raw === null) { return null; } $value = trim($raw); if ($value === '') { return ''; } $map = self::legacyMap($kind); if (isset($map[$value])) { return $map[$value]; } $lower = mb_strtolower($value); foreach ($map as $alias => $code) { if (mb_strtolower((string) $alias) === $lower) { return $code; } } $catalog = self::catalogForKind($kind); if ($catalog !== null) { foreach ($catalog as $code => $labels) { if (mb_strtolower($code) === $lower) { return $code; } if (mb_strtolower((string) ($labels['en'] ?? '')) === $lower) { return $code; } if ((string) ($labels['zh-CN'] ?? '') === $value) { return $code; } } } return $value; } /** * 同一选项的全部等价写法(编码 / 中文 / 英文),用于评审筛查等精确匹配。 * * @return list */ public static function aliases(string $kind, string $raw): array { $value = trim($raw); $normalized = self::normalize($kind, $value); if ($normalized === null || $normalized === '') { return $value !== '' ? [$value] : []; } $out = [$normalized]; if ($value !== '') { $out[] = $value; } $catalog = self::catalogForKind($kind) ?? []; if (isset($catalog[$normalized])) { $zh = trim((string) ($catalog[$normalized]['zh-CN'] ?? '')); $en = trim((string) ($catalog[$normalized]['en'] ?? '')); if ($zh !== '') { $out[] = $zh; if ($kind === 'event_location' && ! str_contains($zh, '赛区')) { $out[] = $zh.'赛区'; } } if ($en !== '') { $out[] = $en; } } foreach (self::legacyMap($kind) as $alias => $code) { if ($code === $normalized) { $out[] = (string) $alias; } } return array_values(array_unique(array_filter( array_map(static fn ($v) => trim((string) $v), $out), static fn ($v) => $v !== '', ))); } /** * @param iterable $values * @return list */ public static function expandAliases(string $kind, iterable $values): array { $out = []; foreach ($values as $value) { foreach (self::aliases($kind, trim((string) $value)) as $alias) { $out[$alias] = true; } } return array_keys($out); } public static function same(string $kind, ?string $left, ?string $right): bool { $a = self::normalize($kind, $left); $b = self::normalize($kind, $right); if ($a === null || $a === '' || $b === null || $b === '') { return false; } return $a === $b; } /** * @return array|null */ private static function catalogForKind(string $kind): ?array { return match ($kind) { 'degree' => self::degrees(), 'location_country' => self::locationCountries(), 'event_location' => self::eventLocations(), 'purpose', 'audience_purpose' => self::audiencePurposes(), default => null, }; } /** * @param array $catalog * @return list */ public static function codes(array $catalog): array { return array_keys($catalog); } /** * @param array $catalog * @return list */ public static function acceptedValues(array $catalog, string $kind): array { return array_values(array_unique([ ...self::codes($catalog), ...array_keys(self::legacyMap($kind)), ])); } /** * @param array $catalog */ public static function label(array $catalog, string $code, string $locale = PortalLocale::ZH): string { $normalized = self::normalize( $catalog === self::degrees() ? 'degree' : ($catalog === self::locationCountries() ? 'location_country' : ($catalog === self::eventLocations() ? 'event_location' : 'purpose')), $code ) ?? $code; $row = $catalog[$normalized] ?? null; if ($row === null) { return $code; } return $locale === PortalLocale::EN ? ($row['en'] ?? $row['zh-CN']) : ($row['zh-CN'] ?? $row['en'] ?? $code); } /** * @param array $catalog * @return list */ public static function schemaOptions(array $catalog): array { $out = []; foreach ($catalog as $code => $labels) { $out[] = [ 'value' => $code, 'label' => $labels['zh-CN'], 'label_i18n' => ['en' => $labels['en']], ]; } return $out; } }