diff --git a/block.js b/assets/block.js similarity index 93% rename from block.js rename to assets/block.js index a00a6cc..c4c2302 100644 --- a/block.js +++ b/assets/block.js @@ -180,6 +180,17 @@ } }, [owner, repo, platform, customDomain, customSiteName]); + // 获取显示用的头像 URL(优先仓库头像) + const getDisplayAvatarUrl = (repoData) => { + if (repoData.repo_avatar_url) { + return repoData.repo_avatar_url; + } + if (repoData.owner && repoData.owner.avatar_url) { + return repoData.owner.avatar_url; + } + return ''; + }; + const renderPreview = () => { if (loading) { return el('div', { className: 'git-embed-loading' }, @@ -209,18 +220,11 @@ const avatarClass = `git-embed-avatar git-embed-avatar-${avatarSize}`; const buttonClass = `git-embed-button-${buttonSize}`; - let downloadUrl = ''; - if (repoData.archive_url) { - const defaultBranch = repoData.default_branch || 'main'; - if (repoData.platform === 'github') { - downloadUrl = repoData.archive_url.replace('{archive_format}', 'zipball').replace('{/ref}', `/${defaultBranch}`); - } else { - downloadUrl = repoData.archive_url; - if (downloadUrl.includes('main.zip') && defaultBranch !== 'main') { - downloadUrl = downloadUrl.replace('main.zip', `${defaultBranch}.zip`); - } - } - } + // 使用简化的下载地址 + const downloadUrl = repoData.archive_url || ''; + + // 获取显示头像 + const displayAvatarUrl = getDisplayAvatarUrl(repoData); return el('div', { className: cardClass }, showSiteInfo && repoData.site_info && el('div', { @@ -243,10 +247,11 @@ el('div', { className: 'git-embed-header' }, el('div', { className: 'git-embed-title-section' }, - showAvatar && repoData.owner && el('img', { - src: repoData.owner.avatar_url, - alt: repoData.owner.login, - className: avatarClass + showAvatar && displayAvatarUrl && el('img', { + src: displayAvatarUrl, + alt: repoData.name, + className: avatarClass, + title: repoData.repo_avatar_url ? 'Repository Avatar' : 'Owner Avatar' }), el('div', { className: 'git-embed-title-content' }, el('h3', { className: 'git-embed-title' }, @@ -264,7 +269,13 @@ target: '_blank', rel: 'noopener', className: 'git-embed-owner-link' - }, `@${repoData.owner.login}`) + }, `@${repoData.owner.login}`), + repoData.repo_avatar_url && el('span', { + className: 'git-embed-repo-avatar-badge', + title: 'Repository has custom avatar' + }, + el('span', { className: 'dashicons dashicons-format-image' }) + ) ) ) ), @@ -319,10 +330,10 @@ el('span', { className: 'dashicons dashicons-admin-page' }), 'Clone' ), - showDownloadButton && el('a', { + showDownloadButton && downloadUrl && el('a', { href: downloadUrl, className: `git-embed-button git-embed-button-secondary ${buttonClass}`, - download: `${repoData.name}.zip` + download: `${repoData.name}-${repoData.default_branch || 'main'}.zip` }, el('span', { className: 'dashicons dashicons-download' }), 'Download ZIP' @@ -427,9 +438,10 @@ onChange: (value) => setAttributes({ showSiteInfo: value }) }), el(ToggleControl, { - label: __('Show Owner Avatar', 'git-embed-feicode'), + label: __('Show Avatar', 'git-embed-feicode'), checked: showAvatar, - onChange: (value) => setAttributes({ showAvatar: value }) + onChange: (value) => setAttributes({ showAvatar: value }), + help: 'Shows repository avatar if available, otherwise owner avatar' }), showAvatar && el(SelectControl, { label: __('Avatar Size', 'git-embed-feicode'), diff --git a/style.css b/assets/style.css similarity index 98% rename from style.css rename to assets/style.css index e49239e..b5b87fa 100644 --- a/style.css +++ b/assets/style.css @@ -179,21 +179,22 @@ border-radius: 15%; flex-shrink: 0; border: 2px solid #e1e4e8; + padding: 8px; } .git-embed-avatar-small { - width: 32px; - height: 32px; + width: 26px; + height: 26px; } .git-embed-avatar-medium { - width: 40px; - height: 40px; + width: 30px; + height: 30px; } .git-embed-avatar-large { - width: 48px; - height: 48px; + width: 35px; + height: 35px; } .git-embed-owner-info { @@ -287,6 +288,7 @@ .git-embed-description .dashicons { margin-top: 2px; flex-shrink: 0; + font-size: 18px; } .git-embed-stats { @@ -513,13 +515,13 @@ line-height: 1.25; } .git-embed-avatar-large { - width: 40px; - height: 40px; + width: 30px; + height: 30px; } .git-embed-avatar-medium { - width: 32px; - height: 32px; + width: 26px; + height: 26px; } .git-embed-owner-info { diff --git a/git-embed-feicode.php b/git-embed-feicode.php index 49d921c..86e9845 100644 --- a/git-embed-feicode.php +++ b/git-embed-feicode.php @@ -3,647 +3,1009 @@ declare(strict_types=1); /** * Plugin Name: Git Embed for feiCode - * Description: Embed Git repositories from GitHub with beautiful cards - * Version: 1.0.0 + * Description: Embed Git repositories from GitHub/Gitlab/Gitea/Forgejo and Self-hosted Git service with beautiful cards + + + * Version: 1.0.1 * Author: feiCode + * Author URI: https://cn.feicode.com * Text Domain: git-embed-feicode * Domain Path: /languages + * Requires at least: 5.0 + * Tested up to: 6.4 + * Requires PHP: 7.4 + * License: GPL v2 or later + * License URI: https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('ABSPATH')) { - exit; +if (!defined("ABSPATH")) { + exit(); } -class GitEmbedFeiCode { - - private const PLUGIN_VERSION = '1.0.0'; - private const BLOCK_NAME = 'git-embed-feicode/repository'; - - public function __construct() { - add_action('init', [$this, 'init']); - add_action('wp_ajax_git_embed_fetch', [$this, 'ajax_fetch_repo']); - add_action('wp_ajax_nopriv_git_embed_fetch', [$this, 'ajax_fetch_repo']); - add_action('wp_ajax_git_embed_clear_cache', [$this, 'ajax_clear_cache']); - register_deactivation_hook(__FILE__, [$this, 'clear_all_cache']); +class GitEmbedFeiCode +{ + private const PLUGIN_VERSION = "1.0.1"; + private const BLOCK_NAME = "git-embed-feicode/repository"; + private const TEXT_DOMAIN = "git-embed-feicode"; + + public function __construct() + { + add_action("init", [$this, "init"]); + add_action("wp_ajax_git_embed_fetch", [$this, "ajax_fetch_repo"]); + add_action("wp_ajax_nopriv_git_embed_fetch", [ + $this, + "ajax_fetch_repo", + ]); + add_action("wp_ajax_git_embed_clear_cache", [ + $this, + "ajax_clear_cache", + ]); + register_deactivation_hook(__FILE__, [$this, "clear_all_cache"]); + + // 加载语言文件 + add_action("plugins_loaded", [$this, "load_textdomain"]); } - - public function init(): void { + + public function init(): void + { $this->register_block(); - $this->load_textdomain(); } - - private function register_block(): void { + + /** + * 加载插件语言文件 + */ + public function load_textdomain(): void + { + load_plugin_textdomain( + self::TEXT_DOMAIN, + false, + dirname(plugin_basename(__FILE__)) . "/languages", + ); + } + + private function register_block(): void + { register_block_type(self::BLOCK_NAME, [ - 'editor_script' => 'git-embed-feicode-editor', - 'editor_style' => 'git-embed-feicode-style', - 'style' => 'git-embed-feicode-style', - 'render_callback' => [$this, 'render_block'], - 'attributes' => [ - 'platform' => [ - 'type' => 'string', - 'default' => 'github' + "editor_script" => "git-embed-feicode-editor", + "editor_style" => "git-embed-feicode-style", + "style" => "git-embed-feicode-style", + "render_callback" => [$this, "render_block"], + "attributes" => [ + "platform" => [ + "type" => "string", + "default" => "github", ], - 'customDomain' => [ - 'type' => 'string', - 'default' => '' + "customDomain" => [ + "type" => "string", + "default" => "", ], - 'customSiteName' => [ - 'type' => 'string', - 'default' => '' + "customSiteName" => [ + "type" => "string", + "default" => "", ], - 'owner' => [ - 'type' => 'string', - 'default' => '' + "owner" => [ + "type" => "string", + "default" => "", ], - 'repo' => [ - 'type' => 'string', - 'default' => '' + "repo" => [ + "type" => "string", + "default" => "", ], - 'showDescription' => [ - 'type' => 'boolean', - 'default' => true + "showDescription" => [ + "type" => "boolean", + "default" => true, ], - 'showStats' => [ - 'type' => 'boolean', - 'default' => true + "showStats" => [ + "type" => "boolean", + "default" => true, ], - 'showLanguage' => [ - 'type' => 'boolean', - 'default' => true + "showLanguage" => [ + "type" => "boolean", + "default" => true, ], - 'showActions' => [ - 'type' => 'boolean', - 'default' => true + "showActions" => [ + "type" => "boolean", + "default" => true, ], - 'showViewButton' => [ - 'type' => 'boolean', - 'default' => true + "showViewButton" => [ + "type" => "boolean", + "default" => true, ], - 'showCloneButton' => [ - 'type' => 'boolean', - 'default' => true + "showCloneButton" => [ + "type" => "boolean", + "default" => true, ], - 'showDownloadButton' => [ - 'type' => 'boolean', - 'default' => true + "showDownloadButton" => [ + "type" => "boolean", + "default" => true, ], - 'cardStyle' => [ - 'type' => 'string', - 'default' => 'default' + "cardStyle" => [ + "type" => "string", + "default" => "default", ], - 'buttonStyle' => [ - 'type' => 'string', - 'default' => 'default' + "buttonStyle" => [ + "type" => "string", + "default" => "default", ], - 'buttonSize' => [ - 'type' => 'string', - 'default' => 'medium' + "buttonSize" => [ + "type" => "string", + "default" => "medium", ], - 'showIssuesButton' => [ - 'type' => 'boolean', - 'default' => false + "showIssuesButton" => [ + "type" => "boolean", + "default" => false, ], - 'showForksButton' => [ - 'type' => 'boolean', - 'default' => false + "showForksButton" => [ + "type" => "boolean", + "default" => false, ], - 'showAvatar' => [ - 'type' => 'boolean', - 'default' => true + "showAvatar" => [ + "type" => "boolean", + "default" => true, ], - 'showSiteInfo' => [ - 'type' => 'boolean', - 'default' => true + "showSiteInfo" => [ + "type" => "boolean", + "default" => true, ], - 'avatarSize' => [ - 'type' => 'string', - 'default' => 'medium' + "avatarSize" => [ + "type" => "string", + "default" => "medium", ], - 'alignment' => [ - 'type' => 'string', - 'default' => 'none' - ] - ] + "alignment" => [ + "type" => "string", + "default" => "none", + ], + ], ]); - + wp_register_script( - 'git-embed-feicode-editor', - plugin_dir_url(__FILE__) . 'block.js', - ['wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n'], - self::PLUGIN_VERSION + "git-embed-feicode-editor", + plugin_dir_url(__FILE__) . "assets/block.js", + [ + "wp-blocks", + "wp-element", + "wp-editor", + "wp-components", + "wp-i18n", + ], + self::PLUGIN_VERSION, ); - + wp_register_style( - 'git-embed-feicode-style', - plugin_dir_url(__FILE__) . 'style.css', + "git-embed-feicode-style", + plugin_dir_url(__FILE__) . "assets/style.css", [], - self::PLUGIN_VERSION + self::PLUGIN_VERSION, ); - - wp_localize_script('git-embed-feicode-editor', 'gitEmbedAjax', [ - 'url' => admin_url('admin-ajax.php'), - 'nonce' => wp_create_nonce('git_embed_nonce'), - 'cache_nonce' => wp_create_nonce('git_embed_cache_nonce') + + wp_set_script_translations( + "git-embed-feicode-editor", + self::TEXT_DOMAIN, + plugin_dir_path(__FILE__) . "languages", + ); + + wp_localize_script("git-embed-feicode-editor", "gitEmbedAjax", [ + "url" => admin_url("admin-ajax.php"), + "nonce" => wp_create_nonce("git_embed_nonce"), + "cache_nonce" => wp_create_nonce("git_embed_cache_nonce"), ]); } - - public function render_block(array $attributes): string { - $owner = sanitize_text_field($attributes['owner'] ?? ''); - $repo = sanitize_text_field($attributes['repo'] ?? ''); - $platform = sanitize_text_field($attributes['platform'] ?? 'github'); - $custom_domain = sanitize_text_field($attributes['customDomain'] ?? ''); - $custom_site_name = sanitize_text_field($attributes['customSiteName'] ?? ''); - + + public function render_block(array $attributes): string + { + $owner = sanitize_text_field($attributes["owner"] ?? ""); + $repo = sanitize_text_field($attributes["repo"] ?? ""); + $platform = sanitize_text_field($attributes["platform"] ?? "github"); + $custom_domain = sanitize_text_field($attributes["customDomain"] ?? ""); + $custom_site_name = sanitize_text_field( + $attributes["customSiteName"] ?? "", + ); + if (empty($owner) || empty($repo)) { - return '
Repository information required
'; + return '
' . + esc_html__( + "Repository information required", + self::TEXT_DOMAIN, + ) . + "
"; } - - if (in_array($platform, ['gitea', 'forgejo', 'gitlab', 'custom']) && empty($custom_domain)) { - return '
Custom domain required for ' . ucfirst($platform) . '
'; + + if ( + in_array($platform, ["gitea", "forgejo", "gitlab", "custom"]) && + empty($custom_domain) + ) { + return '
' . + esc_html( + sprintf( + __("Custom domain required for %s", self::TEXT_DOMAIN), + ucfirst($platform), + ), + ) . + "
"; } - - $repo_data = $this->fetch_repository_data($platform, $owner, $repo, $custom_domain, $custom_site_name); - + + $repo_data = $this->fetch_repository_data( + $platform, + $owner, + $repo, + $custom_domain, + $custom_site_name, + ); + if (!$repo_data) { - return '
Failed to fetch repository data
'; + return '
' . + esc_html__( + "Failed to fetch repository data", + self::TEXT_DOMAIN, + ) . + "
"; } - + return $this->render_repository_card($repo_data, $attributes); } - - private function fetch_repository_data(string $platform, string $owner, string $repo, string $custom_domain = '', string $custom_site_name = ''): ?array { - $cache_key = "git_embed_{$platform}_{$owner}_{$repo}" . ($custom_domain ? "_{$custom_domain}" : '') . ($custom_site_name ? "_{$custom_site_name}" : ''); + + private function fetch_repository_data( + string $platform, + string $owner, + string $repo, + string $custom_domain = "", + string $custom_site_name = "", + ): ?array { + $cache_key = + "git_embed_{$platform}_{$owner}_{$repo}" . + ($custom_domain ? "_{$custom_domain}" : "") . + ($custom_site_name ? "_{$custom_site_name}" : ""); $cached = get_transient($cache_key); - + if ($cached !== false) { return $cached; } - - $api_config = $this->get_api_config($platform, $custom_domain, $custom_site_name); + + $api_config = $this->get_api_config( + $platform, + $custom_domain, + $custom_site_name, + ); if (!$api_config) { return null; } - - $url = $api_config['api_url'] . "/repos/{$owner}/{$repo}"; + + $url = $api_config["api_url"] . "/repos/{$owner}/{$repo}"; $response = wp_remote_get($url, [ - 'timeout' => 15, - 'headers' => [ - 'User-Agent' => 'Git-Embed-FeiCode/1.0', - 'Accept' => 'application/json' - ] + "timeout" => 15, + "headers" => [ + "User-Agent" => "Git-Embed-FeiCode/1.0", + "Accept" => "application/json", + ], ]); - - if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { + + if ( + is_wp_error($response) || + wp_remote_retrieve_response_code($response) !== 200 + ) { return null; } - + $data = json_decode(wp_remote_retrieve_body($response), true); - + if (!$data) { return null; } - - $repo_data = $this->normalize_repository_data($data, $platform, $api_config); - - if (!isset($data['default_branch']) && in_array($platform, ['gitea', 'forgejo', 'custom'])) { - $repo_data['default_branch'] = $this->detect_default_branch($api_config, $owner, $repo); - $repo_data['archive_url'] = $this->get_archive_url(array_merge($data, ['default_branch' => $repo_data['default_branch']]), $platform, $api_config['base_url']); + + $repo_data = $this->normalize_repository_data( + $data, + $platform, + $api_config, + ); + + // 获取默认分支和下载地址 + if ( + !isset($data["default_branch"]) && + in_array($platform, ["gitea", "forgejo", "custom"]) + ) { + $repo_data["default_branch"] = $this->detect_default_branch( + $api_config, + $owner, + $repo, + ); } - + + // 简化下载地址获取 + $repo_data["archive_url"] = $this->get_simple_archive_url( + $platform, + $api_config["base_url"], + $owner, + $repo, + $repo_data["default_branch"], + ); + set_transient($cache_key, $repo_data, DAY_IN_SECONDS); - - if (!empty($repo_data['owner']['avatar_url'])) { - $this->cache_avatar($repo_data['owner']['avatar_url']); + + // 缓存头像(优先仓库头像) + if (!empty($repo_data["repo_avatar_url"])) { + $this->cache_avatar($repo_data["repo_avatar_url"]); + } elseif (!empty($repo_data["owner"]["avatar_url"])) { + $this->cache_avatar($repo_data["owner"]["avatar_url"]); } - + return $repo_data; } - - private function get_api_config(string $platform, string $custom_domain = '', string $custom_site_name = ''): ?array { + + private function get_api_config( + string $platform, + string $custom_domain = "", + string $custom_site_name = "", + ): ?array { switch ($platform) { - case 'github': + case "github": return [ - 'api_url' => 'https://api.github.com', - 'base_url' => 'https://github.com', - 'site_info' => [ - 'name' => 'GitHub', - 'url' => 'https://github.com', - 'favicon' => 'https://github.com/favicon.ico', - 'color' => '#24292f' - ] + "api_url" => "https://api.github.com", + "base_url" => "https://github.com", + "site_info" => [ + "name" => "GitHub", + "url" => "https://github.com", + "favicon" => "https://github.com/favicon.ico", + "color" => "#24292f", + ], ]; - - case 'gitea': + + case "gitea": if (empty($custom_domain)) { return null; } $domain = $this->normalize_domain($custom_domain); - $site_name = $custom_site_name ?: $this->get_site_name($domain, 'Gitea'); + $site_name = + $custom_site_name ?: $this->get_site_name($domain, "Gitea"); return [ - 'api_url' => "https://{$domain}/api/v1", - 'base_url' => "https://{$domain}", - 'site_info' => [ - 'name' => $site_name, - 'url' => "https://{$domain}", - 'favicon' => "https://{$domain}/assets/img/favicon.png", - 'color' => '#609926' - ] + "api_url" => "https://{$domain}/api/v1", + "base_url" => "https://{$domain}", + "site_info" => [ + "name" => $site_name, + "url" => "https://{$domain}", + "favicon" => "https://{$domain}/assets/img/favicon.png", + "color" => "#609926", + ], ]; - - case 'forgejo': + + case "forgejo": if (empty($custom_domain)) { return null; } $domain = $this->normalize_domain($custom_domain); - $site_name = $custom_site_name ?: $this->get_site_name($domain, 'Forgejo'); + $site_name = + $custom_site_name ?: + $this->get_site_name($domain, "Forgejo"); return [ - 'api_url' => "https://{$domain}/api/v1", - 'base_url' => "https://{$domain}", - 'site_info' => [ - 'name' => $site_name, - 'url' => "https://{$domain}", - 'favicon' => "https://{$domain}/assets/img/favicon.png", - 'color' => '#fb923c' - ] + "api_url" => "https://{$domain}/api/v1", + "base_url" => "https://{$domain}", + "site_info" => [ + "name" => $site_name, + "url" => "https://{$domain}", + "favicon" => "https://{$domain}/assets/img/favicon.png", + "color" => "#fb923c", + ], ]; - - case 'gitlab': + + case "gitlab": if (empty($custom_domain)) { return null; } $domain = $this->normalize_domain($custom_domain); - $site_name = $custom_site_name ?: $this->get_site_name($domain, 'GitLab'); + $site_name = + $custom_site_name ?: + $this->get_site_name($domain, "GitLab"); return [ - 'api_url' => "https://{$domain}/api/v4", - 'base_url' => "https://{$domain}", - 'site_info' => [ - 'name' => $site_name, - 'url' => "https://{$domain}", - 'favicon' => "https://{$domain}/assets/favicon.ico", - 'color' => '#fc6d26' - ] + "api_url" => "https://{$domain}/api/v4", + "base_url" => "https://{$domain}", + "site_info" => [ + "name" => $site_name, + "url" => "https://{$domain}", + "favicon" => "https://{$domain}/assets/favicon.ico", + "color" => "#fc6d26", + ], ]; - - case 'custom': + + case "custom": if (empty($custom_domain)) { return null; } $domain = $this->normalize_domain($custom_domain); - $site_name = $custom_site_name ?: $this->get_site_name($domain, 'Git Service'); + $site_name = + $custom_site_name ?: + $this->get_site_name( + $domain, + __("Git Service", self::TEXT_DOMAIN), + ); return [ - 'api_url' => "https://{$domain}/api/v1", - 'base_url' => "https://{$domain}", - 'site_info' => [ - 'name' => $site_name, - 'url' => "https://{$domain}", - 'favicon' => "https://{$domain}/favicon.ico", - 'color' => '#6366f1' - ] + "api_url" => "https://{$domain}/api/v1", + "base_url" => "https://{$domain}", + "site_info" => [ + "name" => $site_name, + "url" => "https://{$domain}", + "favicon" => "https://{$domain}/favicon.ico", + "color" => "#6366f1", + ], ]; - + default: return null; } } - - private function get_site_name(string $domain, string $fallback): string { - $cache_key = 'git_embed_site_name_' . md5($domain); + + private function get_site_name(string $domain, string $fallback): string + { + $cache_key = "git_embed_site_name_" . md5($domain); $cached = get_transient($cache_key); - + if ($cached !== false) { return $cached; } - + $response = wp_remote_get("https://{$domain}", [ - 'timeout' => 10, - 'headers' => [ - 'User-Agent' => 'Git-Embed-FeiCode/1.0' - ] + "timeout" => 10, + "headers" => [ + "User-Agent" => "Git-Embed-FeiCode/1.0", + ], ]); - - if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { + + if ( + !is_wp_error($response) && + wp_remote_retrieve_response_code($response) === 200 + ) { $body = wp_remote_retrieve_body($response); - if (preg_match('/]*>([^<]+)<\/title>/i', $body, $matches)) { - $title = trim(html_entity_decode($matches[1], ENT_QUOTES, 'UTF-8')); + if ( + preg_match("/]*>([^<]+)<\/title>/i", $body, $matches) + ) { + $title = trim( + html_entity_decode($matches[1], ENT_QUOTES, "UTF-8"), + ); if (!empty($title) && strlen($title) < 100) { set_transient($cache_key, $title, DAY_IN_SECONDS); return $title; } } } - + set_transient($cache_key, $fallback, HOUR_IN_SECONDS); return $fallback; } - - private function detect_default_branch(array $api_config, string $owner, string $repo): string { - $branches_to_try = ['main', 'master', 'develop', 'dev']; - $base_url = $api_config['base_url']; - + + private function detect_default_branch( + array $api_config, + string $owner, + string $repo, + ): string { + // 尝试从 API 获取默认分支 + $branches_url = + $api_config["api_url"] . "/repos/{$owner}/{$repo}/branches"; + $response = wp_remote_get($branches_url, [ + "timeout" => 10, + "headers" => [ + "User-Agent" => "Git-Embed-FeiCode/1.0", + "Accept" => "application/json", + ], + ]); + + if ( + !is_wp_error($response) && + wp_remote_retrieve_response_code($response) === 200 + ) { + $branches = json_decode(wp_remote_retrieve_body($response), true); + if (is_array($branches) && !empty($branches)) { + // 查找默认分支(通常是第一个分支或名为 main/master 的分支) + foreach ($branches as $branch) { + if (isset($branch["name"])) { + if (in_array($branch["name"], ["main", "master"])) { + return $branch["name"]; + } + } + } + // 如果没有找到 main/master,返回第一个分支 + if (isset($branches[0]["name"])) { + return $branches[0]["name"]; + } + } + } + + // 如果 API 获取失败,尝试通过下载链接测试 + $branches_to_try = ["main", "master", "develop", "dev"]; + $base_url = $api_config["base_url"]; + foreach ($branches_to_try as $branch) { - $test_url = "{$base_url}/{$owner}/{$repo}/archive/{$branch}.zip"; + $test_url = "{$base_url}/{$owner}/{$repo}/archive/refs/heads/{$branch}.zip"; $response = wp_remote_head($test_url, [ - 'timeout' => 5, - 'headers' => [ - 'User-Agent' => 'Git-Embed-FeiCode/1.0' - ] + "timeout" => 5, + "headers" => [ + "User-Agent" => "Git-Embed-FeiCode/1.0", + ], ]); - - if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { + + if ( + !is_wp_error($response) && + wp_remote_retrieve_response_code($response) === 200 + ) { return $branch; } } - - return 'main'; + + return "main"; } - - private function normalize_domain(string $domain): string { + + private function normalize_domain(string $domain): string + { $domain = trim($domain); - $domain = preg_replace('/^https?:\/\//', '', $domain); - $domain = rtrim($domain, '/'); + $domain = preg_replace("/^https?:\/\//", "", $domain); + $domain = rtrim($domain, "/"); return $domain; } - - private function normalize_repository_data(array $data, string $platform, array $api_config): array { - $base_url = $api_config['base_url']; - - if ($platform === 'gitlab') { + + private function normalize_repository_data( + array $data, + string $platform, + array $api_config, + ): array { + $base_url = $api_config["base_url"]; + + if ($platform === "gitlab") { return [ - 'name' => $data['name'], - 'full_name' => $data['path_with_namespace'] ?? ($data['namespace']['name'] . '/' . $data['name']), - 'description' => $data['description'], - 'html_url' => $data['web_url'], - 'language' => $data['language'] ?? null, - 'stargazers_count' => $data['star_count'] ?? 0, - 'forks_count' => $data['forks_count'] ?? 0, - 'open_issues_count' => $data['open_issues_count'] ?? 0, - 'clone_url' => $data['http_url_to_repo'], - 'archive_url' => $this->get_archive_url($data, $platform, $base_url), - 'default_branch' => $data['default_branch'] ?? 'main', - 'owner' => [ - 'login' => $data['namespace']['name'] ?? $data['owner']['username'], - 'avatar_url' => $data['namespace']['avatar_url'] ?? $data['owner']['avatar_url'], - 'html_url' => $base_url . '/' . ($data['namespace']['name'] ?? $data['owner']['username']), - 'type' => $this->normalize_owner_type($data['namespace']['kind'] ?? $data['owner']['type'] ?? 'user') + "name" => $data["name"], + "full_name" => + $data["path_with_namespace"] ?? + $data["namespace"]["name"] . "/" . $data["name"], + "description" => $data["description"], + "html_url" => $data["web_url"], + "language" => $data["language"] ?? null, + "stargazers_count" => $data["star_count"] ?? 0, + "forks_count" => $data["forks_count"] ?? 0, + "open_issues_count" => $data["open_issues_count"] ?? 0, + "clone_url" => $data["http_url_to_repo"], + "default_branch" => $data["default_branch"] ?? "main", + "repo_avatar_url" => $data["avatar_url"] ?? null, + "owner" => [ + "login" => + $data["namespace"]["name"] ?? + $data["owner"]["username"], + "avatar_url" => + $data["namespace"]["avatar_url"] ?? + $data["owner"]["avatar_url"], + "html_url" => + $base_url . + "/" . + ($data["namespace"]["name"] ?? + $data["owner"]["username"]), + "type" => $this->normalize_owner_type( + $data["namespace"]["kind"] ?? + ($data["owner"]["type"] ?? "user"), + ), ], - 'site_info' => $api_config['site_info'], - 'platform' => $platform + "site_info" => $api_config["site_info"], + "platform" => $platform, ]; } - + + // GitHub, Gitea, Forgejo, Custom return [ - 'name' => $data['name'], - 'full_name' => $data['full_name'] ?? ($data['owner']['login'] . '/' . $data['name']), - 'description' => $data['description'], - 'html_url' => $data['html_url'], - 'language' => $data['language'], - 'stargazers_count' => $data['stargazers_count'] ?? $data['stars_count'] ?? 0, - 'forks_count' => $data['forks_count'] ?? $data['forks'] ?? 0, - 'open_issues_count' => $data['open_issues_count'] ?? $data['open_issues'] ?? 0, - 'clone_url' => $data['clone_url'], - 'archive_url' => $this->get_archive_url($data, $platform, $base_url), - 'default_branch' => $data['default_branch'] ?? 'main', - 'owner' => [ - 'login' => $data['owner']['login'], - 'avatar_url' => $data['owner']['avatar_url'], - 'html_url' => $data['owner']['html_url'] ?? $base_url . '/' . $data['owner']['login'], - 'type' => $this->normalize_owner_type($data['owner']['type'] ?? 'user') + "name" => $data["name"], + "full_name" => + $data["full_name"] ?? + $data["owner"]["login"] . "/" . $data["name"], + "description" => $data["description"], + "html_url" => $data["html_url"], + "language" => $data["language"], + "stargazers_count" => + $data["stargazers_count"] ?? ($data["stars_count"] ?? 0), + "forks_count" => $data["forks_count"] ?? ($data["forks"] ?? 0), + "open_issues_count" => + $data["open_issues_count"] ?? ($data["open_issues"] ?? 0), + "clone_url" => $data["clone_url"], + "default_branch" => $data["default_branch"] ?? "main", + "repo_avatar_url" => $data["avatar_url"] ?? null, + "owner" => [ + "login" => $data["owner"]["login"], + "avatar_url" => $data["owner"]["avatar_url"], + "html_url" => + $data["owner"]["html_url"] ?? + $base_url . "/" . $data["owner"]["login"], + "type" => $this->normalize_owner_type( + $data["owner"]["type"] ?? "user", + ), ], - 'site_info' => $api_config['site_info'], - 'platform' => $platform + "site_info" => $api_config["site_info"], + "platform" => $platform, ]; } - - private function get_archive_url(array $data, string $platform, string $base_url): string { - if (isset($data['archive_url'])) { - return $data['archive_url']; - } - - $owner = $data['owner']['login'] ?? $data['namespace']['name'] ?? ''; - $repo = $data['name']; - $default_branch = $data['default_branch'] ?? 'main'; - + + /** + * 简化的下载地址获取方法 + */ + private function get_simple_archive_url( + string $platform, + string $base_url, + string $owner, + string $repo, + string $branch, + ): string { switch ($platform) { - case 'github': - return "https://api.github.com/repos/{$owner}/{$repo}/zipball/{archive_format}{/ref}"; - case 'gitlab': - $project_id = $data['id'] ?? ''; - return "{$base_url}/api/v4/projects/{$project_id}/repository/archive.zip"; - case 'gitea': - case 'forgejo': - case 'custom': - return "{$base_url}/{$owner}/{$repo}/archive/{$default_branch}.zip"; + case "github": + return "https://github.com/{$owner}/{$repo}/archive/refs/heads/{$branch}.zip"; + + case "gitlab": + return "{$base_url}/{$owner}/{$repo}/-/archive/{$branch}/{$repo}-{$branch}.zip"; + + case "gitea": + case "forgejo": + case "custom": + return "{$base_url}/{$owner}/{$repo}/archive/refs/heads/{$branch}.zip"; + default: - return ''; + return ""; } } - - private function normalize_owner_type(string $type): string { + + private function normalize_owner_type(string $type): string + { $type = strtolower(trim($type)); switch ($type) { - case 'organization': - case 'org': - case 'group': - return 'Organization'; - case 'user': - case 'individual': + case "organization": + case "org": + case "group": + return __("Organization", self::TEXT_DOMAIN); + case "user": + case "individual": default: - return 'User'; + return __("User", self::TEXT_DOMAIN); } } - - private function cache_avatar(string $avatar_url): void { + + private function cache_avatar(string $avatar_url): void + { if (empty($avatar_url)) { return; } - - $cache_key = 'git_embed_avatar_' . md5($avatar_url); - + + $cache_key = "git_embed_avatar_" . md5($avatar_url); + if (get_transient($cache_key) !== false) { return; } - + $response = wp_remote_get($avatar_url, [ - 'timeout' => 10, - 'headers' => [ - 'User-Agent' => 'Git-Embed-FeiCode/1.0' - ] + "timeout" => 10, + "headers" => [ + "User-Agent" => "Git-Embed-FeiCode/1.0", + ], ]); - - if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { + + if ( + !is_wp_error($response) && + wp_remote_retrieve_response_code($response) === 200 + ) { set_transient($cache_key, true, WEEK_IN_SECONDS); } } - - private function render_repository_card(array $repo_data, array $attributes): string { - $show_description = $attributes['showDescription'] ?? true; - $show_stats = $attributes['showStats'] ?? true; - $show_language = $attributes['showLanguage'] ?? true; - $show_actions = $attributes['showActions'] ?? true; - $show_view_button = $attributes['showViewButton'] ?? true; - $show_clone_button = $attributes['showCloneButton'] ?? true; - $show_download_button = $attributes['showDownloadButton'] ?? true; - $show_issues_button = $attributes['showIssuesButton'] ?? false; - $show_forks_button = $attributes['showForksButton'] ?? false; - $show_avatar = $attributes['showAvatar'] ?? true; - $show_site_info = $attributes['showSiteInfo'] ?? true; - $avatar_size = $attributes['avatarSize'] ?? 'medium'; - $card_style = $attributes['cardStyle'] ?? 'default'; - $button_style = $attributes['buttonStyle'] ?? 'default'; - $button_size = $attributes['buttonSize'] ?? 'medium'; - $alignment = $attributes['alignment'] ?? 'none'; - - $align_class = $alignment !== 'none' ? " align{$alignment}" : ''; - $card_class = $card_style !== 'default' ? " git-embed-card-{$card_style}" : ''; + + /** + * 获取显示用的头像 URL(优先仓库头像) + */ + private function get_display_avatar_url(array $repo_data): string + { + // 优先使用仓库头像 + if (!empty($repo_data["repo_avatar_url"])) { + return $repo_data["repo_avatar_url"]; + } + + // 其次使用所有者头像 + if (!empty($repo_data["owner"]["avatar_url"])) { + return $repo_data["owner"]["avatar_url"]; + } + + // 默认头像(可以设置一个占位符头像) + return ""; + } + + private function render_repository_card( + array $repo_data, + array $attributes, + ): string { + $show_description = $attributes["showDescription"] ?? true; + $show_stats = $attributes["showStats"] ?? true; + $show_language = $attributes["showLanguage"] ?? true; + $show_actions = $attributes["showActions"] ?? true; + $show_view_button = $attributes["showViewButton"] ?? true; + $show_clone_button = $attributes["showCloneButton"] ?? true; + $show_download_button = $attributes["showDownloadButton"] ?? true; + $show_issues_button = $attributes["showIssuesButton"] ?? false; + $show_forks_button = $attributes["showForksButton"] ?? false; + $show_avatar = $attributes["showAvatar"] ?? true; + $show_site_info = $attributes["showSiteInfo"] ?? true; + $avatar_size = $attributes["avatarSize"] ?? "medium"; + $card_style = $attributes["cardStyle"] ?? "default"; + $button_style = $attributes["buttonStyle"] ?? "default"; + $button_size = $attributes["buttonSize"] ?? "medium"; + $alignment = $attributes["alignment"] ?? "none"; + + $align_class = $alignment !== "none" ? " align{$alignment}" : ""; + $card_class = + $card_style !== "default" ? " git-embed-card-{$card_style}" : ""; $avatar_class = "git-embed-avatar-{$avatar_size}"; $button_class = "git-embed-button-{$button_size}"; - - $download_url = $this->get_download_url($repo_data); - + + // 使用简化的下载地址 + $download_url = $repo_data["archive_url"]; + + // 获取显示用的头像(优先仓库头像) + $display_avatar_url = $this->get_display_avatar_url($repo_data); + ob_start(); ?> -
+
-
- <?php echo esc_attr($repo_data['site_info']['name']); ?>"> + " + alt="" class="git-embed-site-favicon" loading="lazy" onerror="this.style.display='none'"> - " target="_blank" rel="noopener"> - +
- +
- - <?php echo esc_attr($repo_data['owner']['login']); ?> + + <?php echo esc_attr(
+                                     $repo_data[" + class="git-embed-avatar " + loading="lazy" + title=""> - +
- +
- + - + - - - + + "> +
- - + +

- +

- +
- Stars: - + + - Forks: - + + - Issues: - + +
- - + +
- + - fetch_repository_data($platform, $owner, $repo, $custom_domain, $custom_site_name); - + + $repo_data = $this->fetch_repository_data( + $platform, + $owner, + $repo, + $custom_domain, + $custom_site_name, + ); + if (!$repo_data) { - wp_send_json_error('Failed to fetch repository data'); + wp_send_json_error( + __("Failed to fetch repository", self::TEXT_DOMAIN), + ); } - + wp_send_json_success($repo_data); } - - public function ajax_clear_cache(): void { - check_ajax_referer('git_embed_cache_nonce', 'nonce'); - - if (!current_user_can('manage_options')) { - wp_send_json_error('Insufficient permissions'); + + public function ajax_clear_cache(): void + { + check_ajax_referer("git_embed_cache_nonce", "nonce"); + + if (!current_user_can("manage_options")) { + wp_send_json_error( + __("Insufficient permissions", self::TEXT_DOMAIN), + ); } - - $platform = sanitize_text_field($_POST['platform'] ?? ''); - $custom_domain = sanitize_text_field($_POST['customDomain'] ?? ''); - $custom_site_name = sanitize_text_field($_POST['customSiteName'] ?? ''); - $owner = sanitize_text_field($_POST['owner'] ?? ''); - $repo = sanitize_text_field($_POST['repo'] ?? ''); - + + $platform = sanitize_text_field($_POST["platform"] ?? ""); + $custom_domain = sanitize_text_field($_POST["customDomain"] ?? ""); + $custom_site_name = sanitize_text_field($_POST["customSiteName"] ?? ""); + $owner = sanitize_text_field($_POST["owner"] ?? ""); + $repo = sanitize_text_field($_POST["repo"] ?? ""); + if (empty($owner) || empty($repo)) { - wp_send_json_error('Repository information required'); + wp_send_json_error( + __("Repository information required", self::TEXT_DOMAIN), + ); } - - $this->clear_repository_cache($platform, $owner, $repo, $custom_domain, $custom_site_name); - - wp_send_json_success('Cache cleared successfully'); + + $this->clear_repository_cache( + $platform, + $owner, + $repo, + $custom_domain, + $custom_site_name, + ); + + wp_send_json_success( + __("Cache cleared successfully", self::TEXT_DOMAIN), + ); } - - private function clear_repository_cache(string $platform, string $owner, string $repo, string $custom_domain = '', string $custom_site_name = ''): void { - $cache_key = "git_embed_{$platform}_{$owner}_{$repo}" . ($custom_domain ? "_{$custom_domain}" : '') . ($custom_site_name ? "_{$custom_site_name}" : ''); + + private function clear_repository_cache( + string $platform, + string $owner, + string $repo, + string $custom_domain = "", + string $custom_site_name = "", + ): void { + $cache_key = + "git_embed_{$platform}_{$owner}_{$repo}" . + ($custom_domain ? "_{$custom_domain}" : "") . + ($custom_site_name ? "_{$custom_site_name}" : ""); delete_transient($cache_key); - + if ($custom_domain) { - $site_cache_key = 'git_embed_site_name_' . md5($custom_domain); + $site_cache_key = "git_embed_site_name_" . md5($custom_domain); delete_transient($site_cache_key); } - + global $wpdb; $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", - $wpdb->esc_like('_transient_git_embed_avatar_') . '%' - ) + $wpdb->esc_like("_transient_git_embed_avatar_") . "%", + ), ); $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", - $wpdb->esc_like('_transient_timeout_git_embed_avatar_') . '%' - ) + $wpdb->esc_like("_transient_timeout_git_embed_avatar_") . "%", + ), ); } - - public function clear_all_cache(): void { + + public function clear_all_cache(): void + { global $wpdb; $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", - $wpdb->esc_like('_transient_git_embed_') . '%' - ) + $wpdb->esc_like("_transient_git_embed_") . "%", + ), ); $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", - $wpdb->esc_like('_transient_timeout_git_embed_') . '%' - ) - ); - } - - private function load_textdomain(): void { - load_plugin_textdomain( - 'git-embed-feicode', - false, - dirname(plugin_basename(__FILE__)) . '/languages' + $wpdb->esc_like("_transient_timeout_git_embed_") . "%", + ), ); } } -new GitEmbedFeiCode(); \ No newline at end of file +new GitEmbedFeiCode(); diff --git a/languages/git-embed-feicode-zh_CN.json b/languages/git-embed-feicode-zh_CN.json new file mode 100644 index 0000000..516acec --- /dev/null +++ b/languages/git-embed-feicode-zh_CN.json @@ -0,0 +1,180 @@ +{ + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=1; plural=0;", + "lang": "zh_CN" + }, + "Git Repository": [ + "Git 仓库" + ], + "Embed a Git repository with information and stats": [ + "嵌入包含信息和统计数据的 Git 仓库" + ], + "Repository Settings": [ + "仓库设置" + ], + "Platform": [ + "平台" + ], + "Custom Domain": [ + "自定义域名" + ], + "Custom Site Name (Optional)": [ + "自定义站点名称(可选)" + ], + "Repository Owner": [ + "仓库所有者" + ], + "Repository Name": [ + "仓库名称" + ], + "Display Options": [ + "显示选项" + ], + "Show Site Information": [ + "显示站点信息" + ], + "Show Avatar": [ + "显示头像" + ], + "Avatar Size": [ + "头像大小" + ], + "Show Description": [ + "显示描述" + ], + "Show Programming Language": [ + "显示编程语言" + ], + "Show Statistics": [ + "显示统计数据" + ], + "Show Action Buttons": [ + "显示操作按钮" + ], + "Button Options": [ + "按钮选项" + ], + "Show View Repository Button": [ + "显示查看仓库按钮" + ], + "Show Clone Button": [ + "显示克隆按钮" + ], + "Show Download ZIP Button": [ + "显示下载 ZIP 按钮" + ], + "Show Issues Button": [ + "显示议题按钮" + ], + "Show Forks Button": [ + "显示分叉按钮" + ], + "Button Style": [ + "按钮样式" + ], + "Button Size": [ + "按钮大小" + ], + "Style Options": [ + "样式选项" + ], + "Card Style": [ + "卡片样式" + ], + "Please enter repository owner and name": [ + "请输入仓库所有者和名称" + ], + "Please enter custom domain for %s": [ + "请输入 %s 的自定义域名" + ], + "Fetching repository data...": [ + "正在获取仓库数据..." + ], + "Failed to fetch repository": [ + "获取仓库失败" + ], + "Network error occurred": [ + "网络错误" + ], + "Configure your repository details in the sidebar": [ + "在侧边栏配置您的仓库详情" + ], + "Fetch Repository": [ + "获取仓库" + ], + "Fetching...": [ + "正在获取..." + ], + "Self-hosted Git service requires custom domain": [ + "自托管 Git 服务需要自定义域名" + ], + "Enter the domain of your %s instance": [ + "输入您的 %s 实例域名" + ], + "Override the automatically detected site name": [ + "覆盖自动检测的站点名称" + ], + "Shows repository avatar if available, otherwise owner avatar": [ + "如果可用,显示仓库头像,否则显示所有者头像" + ], + "GitHub": [ + "GitHub" + ], + "Gitea": [ + "Gitea" + ], + "Forgejo": [ + "Forgejo" + ], + "GitLab (Self-hosted)": [ + "GitLab(自托管)" + ], + "Custom Git Service": [ + "自定义 Git 服务" + ], + "Small": [ + "小" + ], + "Medium": [ + "中" + ], + "Large": [ + "大" + ], + "Default": [ + "默认" + ], + "Primary (Green)": [ + "主要(绿色)" + ], + "Secondary (Gray)": [ + "次要(灰色)" + ], + "Outline": [ + "轮廓" + ], + "Ghost": [ + "幽灵" + ], + "Minimal": [ + "简约" + ], + "Bordered": [ + "边框" + ], + "Shadow": [ + "阴影" + ], + "Gradient": [ + "渐变" + ], + "Glassmorphism": [ + "玻璃态" + ] + } + } +} \ No newline at end of file diff --git a/languages/git-embed-feicode-zh_CN.mo b/languages/git-embed-feicode-zh_CN.mo new file mode 100644 index 0000000..a4ccdbb Binary files /dev/null and b/languages/git-embed-feicode-zh_CN.mo differ diff --git a/languages/git-embed-feicode-zh_CN.po b/languages/git-embed-feicode-zh_CN.po new file mode 100644 index 0000000..9930d2d --- /dev/null +++ b/languages/git-embed-feicode-zh_CN.po @@ -0,0 +1,298 @@ +# Copyright (C) 2024 feiCode +# This file is distributed under the same license as the Git Embed for feiCode plugin. +# Translators: +# feiCode Team, 2024 +msgid "" +msgstr "" +"Project-Id-Version: Git Embed for feiCode 1.0.1\n" +"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/git-embed-feicode\n" +"POT-Creation-Date: 2024-12-31 12:00+0000\n" +"PO-Revision-Date: 2025-07-31 17:43+0800\n" +"Last-Translator: feiCode Team\n" +"Language-Team: Chinese (China)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Poedit 3.6\n" + +#. Plugin Name of the plugin/theme +msgid "Git Embed for feiCode" +msgstr "Git 仓库嵌入" + +#. Plugin Description of the plugin/theme +msgid "Embed Git repositories from GitHub/Gitlab/Gitea/Forgejo and Self-hosted Git service with beautiful card" +msgstr "使用精美卡片嵌入 Git 仓库" + +#. Author of the plugin/theme +msgid "feiCode" +msgstr "菲码源库" + +#: block.js:15 +msgid "Git Repository" +msgstr "Git 仓库" + +#: block.js:16 +msgid "Embed a Git repository with information and stats" +msgstr "嵌入包含信息和统计数据的 Git 仓库" + +#: block.js:170 +msgid "Repository Settings" +msgstr "仓库设置" + +#: block.js:174 +msgid "Platform" +msgstr "平台" + +#: block.js:185 +msgid "Custom Domain" +msgstr "自定义域名" + +#: block.js:195 +msgid "Custom Site Name (Optional)" +msgstr "自定义站点名称(可选)" + +#: block.js:205 +msgid "Repository Owner" +msgstr "仓库所有者" + +#: block.js:214 +msgid "Repository Name" +msgstr "仓库名称" + +#: block.js:227 +msgid "Display Options" +msgstr "显示选项" + +#: block.js:231 +msgid "Show Site Information" +msgstr "显示站点信息" + +#: block.js:235 +msgid "Show Avatar" +msgstr "显示头像" + +#: block.js:240 +msgid "Avatar Size" +msgstr "头像大小" + +#: block.js:252 +msgid "Show Description" +msgstr "显示描述" + +#: block.js:256 +msgid "Show Programming Language" +msgstr "显示编程语言" + +#: block.js:260 +msgid "Show Statistics" +msgstr "显示统计数据" + +#: block.js:264 +msgid "Show Action Buttons" +msgstr "显示操作按钮" + +#: block.js:269 +msgid "Button Options" +msgstr "按钮选项" + +#: block.js:273 +msgid "Show View Repository Button" +msgstr "显示查看仓库按钮" + +#: block.js:278 +msgid "Show Clone Button" +msgstr "显示克隆按钮" + +#: block.js:283 +msgid "Show Download ZIP Button" +msgstr "显示下载 ZIP 按钮" + +#: block.js:288 +msgid "Show Issues Button" +msgstr "显示议题按钮" + +#: block.js:293 +msgid "Show Forks Button" +msgstr "显示分叉按钮" + +#: block.js:298 +msgid "Button Style" +msgstr "按钮样式" + +#: block.js:312 +msgid "Button Size" +msgstr "按钮大小" + +#: block.js:326 +msgid "Style Options" +msgstr "样式选项" + +#: block.js:330 +msgid "Card Style" +msgstr "卡片样式" + +#: git-embed-feicode.php:85 +msgid "Repository information required" +msgstr "需要仓库信息" + +#: git-embed-feicode.php:89 +msgid "Custom domain required for %s" +msgstr "%s 需要自定义域名" + +#: git-embed-feicode.php:95 +msgid "Failed to fetch repository data" +msgstr "获取仓库数据失败" + +#: git-embed-feicode.php:672 +msgid "Insufficient permissions" +msgstr "权限不足" + +#: git-embed-feicode.php:684 +msgid "Cache cleared successfully" +msgstr "缓存清理成功" + +#. Error messages +msgid "Please enter repository owner and name" +msgstr "请输入仓库所有者和名称" + +#, javascript-format +msgid "Please enter custom domain for %s" +msgstr "请输入 %s 的自定义域名" + +msgid "Fetching repository data..." +msgstr "正在获取仓库数据..." + +msgid "Failed to fetch repository" +msgstr "获取仓库失败" + +msgid "Network error occurred" +msgstr "网络错误" + +msgid "Configure your repository details in the sidebar" +msgstr "在侧边栏配置您的仓库详情" + +msgid "Fetch Repository" +msgstr "获取仓库" + +msgid "Fetching..." +msgstr "正在获取..." + +#. Help texts +msgid "Self-hosted Git service requires custom domain" +msgstr "自托管 Git 服务需要自定义域名" + +#, javascript-format +msgid "Enter the domain of your %s instance" +msgstr "输入您的 %s 实例域名" + +msgid "Override the automatically detected site name" +msgstr "覆盖自动检测的站点名称" + +msgid "Shows repository avatar if available, otherwise owner avatar" +msgstr "如果可用,显示仓库头像,否则显示所有者头像" + +#. Button labels +msgid "View Repository" +msgstr "查看仓库" + +msgid "Clone" +msgstr "克隆" + +msgid "Download ZIP" +msgstr "下载 ZIP" + +msgid "Issues" +msgstr "议题" + +msgid "Forks" +msgstr "分叉" + +msgid "Copied!" +msgstr "已复制!" + +#. Stats labels +msgid "Stars:" +msgstr "星标:" + +msgid "Forks:" +msgstr "分叉:" + +msgid "Issues:" +msgstr "议题:" + +#. Options +msgid "GitHub" +msgstr "GitHub" + +msgid "Gitea" +msgstr "Gitea" + +msgid "Forgejo" +msgstr "Forgejo" + +msgid "GitLab (Self-hosted)" +msgstr "GitLab(自托管)" + +msgid "Custom Git Service" +msgstr "自定义 Git 服务" + +msgid "Small" +msgstr "小" + +msgid "Medium" +msgstr "中" + +msgid "Large" +msgstr "大" + +msgid "Default" +msgstr "默认" + +msgid "Primary (Green)" +msgstr "主要(绿色)" + +msgid "Secondary (Gray)" +msgstr "次要(灰色)" + +msgid "Outline" +msgstr "轮廓" + +msgid "Ghost" +msgstr "幽灵" + +msgid "Minimal" +msgstr "简约" + +msgid "Bordered" +msgstr "边框" + +msgid "Shadow" +msgstr "阴影" + +msgid "Gradient" +msgstr "渐变" + +msgid "Glassmorphism" +msgstr "玻璃态" + +#. Tooltips and titles +msgid "Click to copy clone URL" +msgstr "点击复制克隆链接" + +msgid "Repository Avatar" +msgstr "仓库头像" + +msgid "Owner Avatar" +msgstr "所有者头像" + +msgid "Repository has custom avatar" +msgstr "仓库有自定义头像" + +#. Owner types +msgid "Organization" +msgstr "组织" + +msgid "User" +msgstr "用户" diff --git a/languages/git-embed-feicode-zh_CN.pot b/languages/git-embed-feicode-zh_CN.pot new file mode 100644 index 0000000..6ad0c21 --- /dev/null +++ b/languages/git-embed-feicode-zh_CN.pot @@ -0,0 +1,296 @@ +# Copyright (C) 2024 feiCode +# This file is distributed under the same license as the Git Embed for feiCode plugin. +msgid "" +msgstr "" +"Project-Id-Version: Git Embed for feiCode 1.0.1\n" +"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/git-embed-feicode\n" +"POT-Creation-Date: 2024-12-31 12:00+0000\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"X-Generator: WordPress POT Generator\n" + +#. Plugin Name of the plugin/theme +msgid "Git Embed for feiCode" +msgstr "" + +#. Plugin Description of the plugin/theme +msgid "Embed Git repositories from GitHub/Gitlab/Gitea/Forgejo and Self-hosted Git service with beautiful cards + +" +msgstr "" + +#. Author of the plugin/theme +msgid "feiCode" +msgstr "" + +#: block.js:15 +msgid "Git Repository" +msgstr "" + +#: block.js:16 +msgid "Embed a Git repository with information and stats" +msgstr "" + +#: block.js:170 +msgid "Repository Settings" +msgstr "" + +#: block.js:174 +msgid "Platform" +msgstr "" + +#: block.js:185 +msgid "Custom Domain" +msgstr "" + +#: block.js:195 +msgid "Custom Site Name (Optional)" +msgstr "" + +#: block.js:205 +msgid "Repository Owner" +msgstr "" + +#: block.js:214 +msgid "Repository Name" +msgstr "" + +#: block.js:227 +msgid "Display Options" +msgstr "" + +#: block.js:231 +msgid "Show Site Information" +msgstr "" + +#: block.js:235 +msgid "Show Avatar" +msgstr "" + +#: block.js:240 +msgid "Avatar Size" +msgstr "" + +#: block.js:252 +msgid "Show Description" +msgstr "" + +#: block.js:256 +msgid "Show Programming Language" +msgstr "" + +#: block.js:260 +msgid "Show Statistics" +msgstr "" + +#: block.js:264 +msgid "Show Action Buttons" +msgstr "" + +#: block.js:269 +msgid "Button Options" +msgstr "" + +#: block.js:273 +msgid "Show View Repository Button" +msgstr "" + +#: block.js:278 +msgid "Show Clone Button" +msgstr "" + +#: block.js:283 +msgid "Show Download ZIP Button" +msgstr "" + +#: block.js:288 +msgid "Show Issues Button" +msgstr "" + +#: block.js:293 +msgid "Show Forks Button" +msgstr "" + +#: block.js:298 +msgid "Button Style" +msgstr "" + +#: block.js:312 +msgid "Button Size" +msgstr "" + +#: block.js:326 +msgid "Style Options" +msgstr "" + +#: block.js:330 +msgid "Card Style" +msgstr "" + +#: git-embed-feicode.php:85 +msgid "Repository information required" +msgstr "" + +#: git-embed-feicode.php:89 +msgid "Custom domain required for %s" +msgstr "" + +#: git-embed-feicode.php:95 +msgid "Failed to fetch repository data" +msgstr "" + +#: git-embed-feicode.php:672 +msgid "Insufficient permissions" +msgstr "" + +#: git-embed-feicode.php:684 +msgid "Cache cleared successfully" +msgstr "" + +#. Error messages +msgid "Please enter repository owner and name" +msgstr "" + +#, javascript-format +msgid "Please enter custom domain for %s" +msgstr "" + +msgid "Fetching repository data..." +msgstr "" + +msgid "Failed to fetch repository" +msgstr "" + +msgid "Network error occurred" +msgstr "" + +msgid "Configure your repository details in the sidebar" +msgstr "" + +msgid "Fetch Repository" +msgstr "" + +msgid "Fetching..." +msgstr "" + +#. Help texts +msgid "Self-hosted Git service requires custom domain" +msgstr "" + +#, javascript-format +msgid "Enter the domain of your %s instance" +msgstr "" + +msgid "Override the automatically detected site name" +msgstr "" + +msgid "Shows repository avatar if available, otherwise owner avatar" +msgstr "" + +#. Button labels +msgid "View Repository" +msgstr "" + +msgid "Clone" +msgstr "" + +msgid "Download ZIP" +msgstr "" + +msgid "Issues" +msgstr "" + +msgid "Forks" +msgstr "" + +msgid "Copied!" +msgstr "" + +#. Stats labels +msgid "Stars:" +msgstr "" + +msgid "Forks:" +msgstr "" + +msgid "Issues:" +msgstr "" + +#. Options +msgid "GitHub" +msgstr "" + +msgid "Gitea" +msgstr "" + +msgid "Forgejo" +msgstr "" + +msgid "GitLab (Self-hosted)" +msgstr "" + +msgid "Custom Git Service" +msgstr "" + +msgid "Small" +msgstr "" + +msgid "Medium" +msgstr "" + +msgid "Large" +msgstr "" + +msgid "Default" +msgstr "" + +msgid "Primary (Green)" +msgstr "" + +msgid "Secondary (Gray)" +msgstr "" + +msgid "Outline" +msgstr "" + +msgid "Ghost" +msgstr "" + +msgid "Minimal" +msgstr "" + +msgid "Bordered" +msgstr "" + +msgid "Shadow" +msgstr "" + +msgid "Gradient" +msgstr "" + +msgid "Glassmorphism" +msgstr "" + +#. Tooltips and titles +msgid "Click to copy clone URL" +msgstr "" + +msgid "Repository Avatar" +msgstr "" + +msgid "Owner Avatar" +msgstr "" + +msgid "Repository has custom avatar" +msgstr "" + +#. Owner types +msgid "Organization" +msgstr "" + +msgid "User" +msgstr ""