diff --git a/assets/block.js b/assets/block.js index c4c2302..b1ec3ce 100644 --- a/assets/block.js +++ b/assets/block.js @@ -131,12 +131,12 @@ const fetchRepoData = () => { if (!owner || !repo) { - setError('Please enter repository owner and name'); + setError(__('Please enter repository owner and name', 'git-embed-feicode')); return; } if ((platform === 'gitea' || platform === 'forgejo' || platform === 'gitlab' || platform === 'custom') && !customDomain) { - setError(`Please enter custom domain for ${platform.charAt(0).toUpperCase() + platform.slice(1)}`); + setError(__('Please enter custom domain for', 'git-embed-feicode') + ' ' + platform.charAt(0).toUpperCase() + platform.slice(1)); return; } @@ -163,13 +163,13 @@ setRepoData(data.data); setError(''); } else { - setError(data.data || 'Failed to fetch repository'); + setError(data.data || __('Failed to fetch repository', 'git-embed-feicode')); setRepoData(null); } }) .catch(err => { setLoading(false); - setError('Network error occurred'); + setError(__('Network error occurred', 'git-embed-feicode')); setRepoData(null); }); }; @@ -180,7 +180,6 @@ } }, [owner, repo, platform, customDomain, customSiteName]); - // 获取显示用的头像 URL(优先仓库头像) const getDisplayAvatarUrl = (repoData) => { if (repoData.repo_avatar_url) { return repoData.repo_avatar_url; @@ -191,11 +190,15 @@ return ''; }; + const handleDownload = (url, filename) => { + window.open(url, '_blank'); + }; + const renderPreview = () => { if (loading) { return el('div', { className: 'git-embed-loading' }, el(Spinner), - el('p', null, 'Fetching repository data...') + el('p', null, __('Fetching repository data...', 'git-embed-feicode')) ); } @@ -210,8 +213,8 @@ return el('div', { className: 'git-embed-placeholder' }, el('div', { className: 'git-embed-placeholder-content' }, el('span', { className: 'dashicons dashicons-admin-links git-embed-placeholder-icon' }), - el('h3', null, 'Git Repository Embed'), - el('p', null, 'Configure your repository details in the sidebar') + el('h3', null, __('Git Repository Embed', 'git-embed-feicode')), + el('p', null, __('Configure your repository details in the sidebar', 'git-embed-feicode')) ) ); } @@ -220,10 +223,13 @@ const avatarClass = `git-embed-avatar git-embed-avatar-${avatarSize}`; const buttonClass = `git-embed-button-${buttonSize}`; - // 使用简化的下载地址 - const downloadUrl = repoData.archive_url || ''; + const downloadInfo = repoData.download_info || {}; + const downloadUrl = downloadInfo.url || repoData.archive_url || ''; + const downloadFilename = downloadInfo.filename || `${repoData.name}.zip`; + const downloadTitle = downloadInfo.name ? + __('Download', 'git-embed-feicode') + ' ' + downloadInfo.name + ' (' + downloadInfo.version + ')' : + __('Download ZIP', 'git-embed-feicode'); - // 获取显示头像 const displayAvatarUrl = getDisplayAvatarUrl(repoData); return el('div', { className: cardClass }, @@ -251,7 +257,7 @@ src: displayAvatarUrl, alt: repoData.name, className: avatarClass, - title: repoData.repo_avatar_url ? 'Repository Avatar' : 'Owner Avatar' + title: repoData.repo_avatar_url ? __('Repository Avatar', 'git-embed-feicode') : __('Owner Avatar', 'git-embed-feicode') }), el('div', { className: 'git-embed-title-content' }, el('h3', { className: 'git-embed-title' }, @@ -272,9 +278,9 @@ }, `@${repoData.owner.login}`), repoData.repo_avatar_url && el('span', { className: 'git-embed-repo-avatar-badge', - title: 'Repository has custom avatar' + title: __('Repository has custom avatar', 'git-embed-feicode') }, - el('span', { className: 'dashicons dashicons-format-image' }) + el('span', { className: '' }) ) ) ) @@ -292,23 +298,23 @@ showDescription && repoData.description && el('p', { className: 'git-embed-description' }, - el('span', { className: 'dashicons dashicons-text-page' }), + el('span', { className: 'dashicons dashicons-editor-quote' }), repoData.description ), showStats && el('div', { className: 'git-embed-stats' }, el('span', { className: 'git-embed-stat' }, el('span', { className: 'dashicons dashicons-star-filled' }), - el('span', { className: 'git-embed-stat-label' }, 'Stars:'), + el('span', { className: 'git-embed-stat-label' }, __('Stars:', 'git-embed-feicode')), el('span', { className: 'git-embed-stat-value' }, repoData.stargazers_count.toLocaleString()) ), el('span', { className: 'git-embed-stat' }, el('span', { className: 'dashicons dashicons-networking' }), - el('span', { className: 'git-embed-stat-label' }, 'Forks:'), + el('span', { className: 'git-embed-stat-label' }, __('Forks:', 'git-embed-feicode')), el('span', { className: 'git-embed-stat-value' }, repoData.forks_count.toLocaleString()) ), el('span', { className: 'git-embed-stat' }, el('span', { className: 'dashicons dashicons-editor-help' }), - el('span', { className: 'git-embed-stat-label' }, 'Issues:'), + el('span', { className: 'git-embed-stat-label' }, __('Issues:', 'git-embed-feicode')), el('span', { className: 'git-embed-stat-value' }, repoData.open_issues_count.toLocaleString()) ) ), @@ -321,22 +327,24 @@ rel: 'noopener' }, el('span', { className: 'dashicons dashicons-external' }), - 'View Repository' + __('View Repository', 'git-embed-feicode') ), showCloneButton && el('span', { className: `git-embed-button git-embed-button-secondary ${buttonClass}`, - title: `Clone URL: ${repoData.clone_url}` + title: __('Clone URL:', 'git-embed-feicode') + ' ' + repoData.clone_url }, el('span', { className: 'dashicons dashicons-admin-page' }), - 'Clone' + __('Clone', 'git-embed-feicode') ), - showDownloadButton && downloadUrl && el('a', { - href: downloadUrl, + showDownloadButton && downloadUrl && el('button', { className: `git-embed-button git-embed-button-secondary ${buttonClass}`, - download: `${repoData.name}-${repoData.default_branch || 'main'}.zip` + onClick: () => handleDownload(downloadUrl, downloadFilename), + title: downloadTitle }, el('span', { className: 'dashicons dashicons-download' }), - 'Download ZIP' + downloadInfo.type === 'release' && downloadInfo.version ? + __('Download', 'git-embed-feicode') + ' ' + downloadInfo.version : + __('Download ZIP', 'git-embed-feicode') ), showIssuesButton && el('a', { href: `${repoData.html_url}/issues`, @@ -345,7 +353,7 @@ rel: 'noopener' }, el('span', { className: 'dashicons dashicons-editor-help' }), - `Issues (${repoData.open_issues_count.toLocaleString()})` + __('Issues', 'git-embed-feicode') + ' (' + repoData.open_issues_count.toLocaleString() + ')' ), showForksButton && el('a', { href: `${repoData.html_url}/forks`, @@ -354,7 +362,7 @@ rel: 'noopener' }, el('span', { className: 'dashicons dashicons-networking' }), - `Forks (${repoData.forks_count.toLocaleString()})` + __('Forks', 'git-embed-feicode') + ' (' + repoData.forks_count.toLocaleString() + ')' ) ) ); @@ -376,14 +384,14 @@ label: __('Platform', 'git-embed-feicode'), value: platform, options: [ - { label: 'GitHub', value: 'github' }, - { label: 'Gitea', value: 'gitea' }, - { label: 'Forgejo', value: 'forgejo' }, - { label: 'GitLab (Self-hosted)', value: 'gitlab' }, - { label: 'Custom Git Service', value: 'custom' } + { label: __('GitHub', 'git-embed-feicode'), value: 'github' }, + { label: __('Gitea', 'git-embed-feicode'), value: 'gitea' }, + { label: __('Forgejo', 'git-embed-feicode'), value: 'forgejo' }, + { label: __('GitLab (Self-hosted)', 'git-embed-feicode'), value: 'gitlab' }, + { label: __('Custom Git Service', 'git-embed-feicode'), value: 'custom' } ], onChange: (value) => setAttributes({ platform: value }), - help: platform !== 'github' ? 'Self-hosted Git service requires custom domain' : '', + help: platform !== 'github' ? __('Self-hosted Git service requires custom domain', 'git-embed-feicode') : '', __next40pxDefaultSize: true, __nextHasNoMarginBottom: true }), @@ -391,8 +399,8 @@ label: __('Custom Domain', 'git-embed-feicode'), value: customDomain, onChange: (value) => setAttributes({ customDomain: value }), - placeholder: 'e.g. git.example.com', - help: `Enter the domain of your ${platform.charAt(0).toUpperCase() + platform.slice(1)} instance`, + placeholder: __('e.g. git.example.com', 'git-embed-feicode'), + help: __('Enter the domain of your', 'git-embed-feicode') + ' ' + platform.charAt(0).toUpperCase() + platform.slice(1) + ' ' + __('instance', 'git-embed-feicode'), __next40pxDefaultSize: true, __nextHasNoMarginBottom: true }), @@ -400,8 +408,8 @@ label: __('Custom Site Name (Optional)', 'git-embed-feicode'), value: customSiteName, onChange: (value) => setAttributes({ customSiteName: value }), - placeholder: 'e.g. Company Git', - help: 'Override the automatically detected site name', + placeholder: __('e.g. Company Git', 'git-embed-feicode'), + help: __('Override the automatically detected site name', 'git-embed-feicode'), __next40pxDefaultSize: true, __nextHasNoMarginBottom: true }), @@ -409,7 +417,7 @@ label: __('Repository Owner', 'git-embed-feicode'), value: owner, onChange: (value) => setAttributes({ owner: value }), - placeholder: 'e.g. facebook', + placeholder: __('e.g. facebook', 'git-embed-feicode'), __next40pxDefaultSize: true, __nextHasNoMarginBottom: true }), @@ -417,7 +425,7 @@ label: __('Repository Name', 'git-embed-feicode'), value: repo, onChange: (value) => setAttributes({ repo: value }), - placeholder: 'e.g. react', + placeholder: __('e.g. react', 'git-embed-feicode'), __next40pxDefaultSize: true, __nextHasNoMarginBottom: true }), @@ -426,7 +434,7 @@ onClick: fetchRepoData, disabled: loading || !owner || !repo || (platform !== 'github' && !customDomain) - }, loading ? 'Fetching...' : 'Fetch Repository') + }, loading ? __('Fetching...', 'git-embed-feicode') : __('Fetch Repository', 'git-embed-feicode')) ), el(PanelBody, { title: __('Display Options', 'git-embed-feicode'), @@ -441,15 +449,15 @@ label: __('Show Avatar', 'git-embed-feicode'), checked: showAvatar, onChange: (value) => setAttributes({ showAvatar: value }), - help: 'Shows repository avatar if available, otherwise owner avatar' + help: __('Shows repository avatar if available, otherwise owner avatar', 'git-embed-feicode') }), showAvatar && el(SelectControl, { label: __('Avatar Size', 'git-embed-feicode'), value: avatarSize, options: [ - { label: 'Small', value: 'small' }, - { label: 'Medium', value: 'medium' }, - { label: 'Large', value: 'large' } + { label: __('Small', 'git-embed-feicode'), value: 'small' }, + { label: __('Medium', 'git-embed-feicode'), value: 'medium' }, + { label: __('Large', 'git-embed-feicode'), value: 'large' } ], onChange: (value) => setAttributes({ avatarSize: value }), __next40pxDefaultSize: true, @@ -514,11 +522,11 @@ label: __('Button Style', 'git-embed-feicode'), value: buttonStyle, options: [ - { label: 'Default', value: 'default' }, - { label: 'Primary (Green)', value: 'primary' }, - { label: 'Secondary (Gray)', value: 'secondary' }, - { label: 'Outline', value: 'outline' }, - { label: 'Ghost', value: 'ghost' } + { label: __('Default', 'git-embed-feicode'), value: 'default' }, + { label: __('Primary (Green)', 'git-embed-feicode'), value: 'primary' }, + { label: __('Secondary (Gray)', 'git-embed-feicode'), value: 'secondary' }, + { label: __('Outline', 'git-embed-feicode'), value: 'outline' }, + { label: __('Ghost', 'git-embed-feicode'), value: 'ghost' } ], onChange: (value) => setAttributes({ buttonStyle: value }), disabled: !showActions, @@ -529,9 +537,9 @@ label: __('Button Size', 'git-embed-feicode'), value: buttonSize, options: [ - { label: 'Small', value: 'small' }, - { label: 'Medium', value: 'medium' }, - { label: 'Large', value: 'large' } + { label: __('Small', 'git-embed-feicode'), value: 'small' }, + { label: __('Medium', 'git-embed-feicode'), value: 'medium' }, + { label: __('Large', 'git-embed-feicode'), value: 'large' } ], onChange: (value) => setAttributes({ buttonSize: value }), disabled: !showActions, @@ -547,12 +555,12 @@ label: __('Card Style', 'git-embed-feicode'), value: cardStyle, options: [ - { label: 'Default', value: 'default' }, - { label: 'Minimal', value: 'minimal' }, - { label: 'Bordered', value: 'bordered' }, - { label: 'Shadow', value: 'shadow' }, - { label: 'Gradient', value: 'gradient' }, - { label: 'Glassmorphism', value: 'glass' } + { label: __('Default', 'git-embed-feicode'), value: 'default' }, + { label: __('Minimal', 'git-embed-feicode'), value: 'minimal' }, + { label: __('Bordered', 'git-embed-feicode'), value: 'bordered' }, + { label: __('Shadow', 'git-embed-feicode'), value: 'shadow' }, + { label: __('Gradient', 'git-embed-feicode'), value: 'gradient' }, + { label: __('Glassmorphism', 'git-embed-feicode'), value: 'glass' } ], onChange: (value) => setAttributes({ cardStyle: value }), __next40pxDefaultSize: true, diff --git a/git-embed-feicode.php b/git-embed-feicode.php index e65aa38..94284b8 100644 --- a/git-embed-feicode.php +++ b/git-embed-feicode.php @@ -4,7 +4,7 @@ declare(strict_types=1); /** * Plugin Name: Git Embed for feiCode * Description: Embed Git repositories from GitHub/Gitlab/Gitea/Forgejo and Self-hosted Git service with beautiful cards - * Version: 1.0.1 + * Version: 1.0.2 * Author: feiCode * Author URI: https://cn.feicode.com * Text Domain: git-embed-feicode @@ -22,7 +22,7 @@ if (!defined("ABSPATH")) { class GitEmbedFeiCode { - private const PLUGIN_VERSION = "1.0.1"; + private const PLUGIN_VERSION = "1.0.2"; private const BLOCK_NAME = "git-embed-feicode/repository"; private const TEXT_DOMAIN = "git-embed-feicode"; @@ -40,7 +40,6 @@ class GitEmbedFeiCode ]); register_deactivation_hook(__FILE__, [$this, "clear_all_cache"]); - // 加载语言文件 add_action("plugins_loaded", [$this, "load_textdomain"]); } @@ -49,9 +48,6 @@ class GitEmbedFeiCode $this->register_block(); } - /** - * 加载插件语言文件 - */ public function load_textdomain(): void { load_plugin_textdomain( @@ -249,77 +245,47 @@ class GitEmbedFeiCode string $custom_domain = "", string $custom_site_name = "", ): ?array { - $cache_key = - "git_embed_{$platform}_{$owner}_{$repo}" . + $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) { + $this->log_debug("Failed to get API config for platform: {$platform}"); return null; } - $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", - ], - ]); - - if ( - is_wp_error($response) || - wp_remote_retrieve_response_code($response) !== 200 - ) { + $repo_data = $this->fetch_repository_info($api_config, $owner, $repo, $platform); + if (!$repo_data) { 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, + $latest_release = $this->fetch_latest_release($api_config, $owner, $repo, $platform); + + $repo_data["download_info"] = $this->generate_download_info( + $platform, + $api_config, + $owner, + $repo, + $repo_data, + $latest_release ); - // 获取默认分支和下载地址 - 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"] = $repo_data["download_info"]["url"]; - // 简化下载地址获取 - $repo_data["archive_url"] = $this->get_simple_archive_url( - $platform, - $api_config["base_url"], - $owner, - $repo, - $repo_data["default_branch"], - ); + $this->log_debug("Platform: {$platform}"); + $this->log_debug("API URL: " . $api_config["api_url"]); + $this->log_debug("Base URL: " . $api_config["base_url"]); + $this->log_debug("Final download URL: " . $repo_data["archive_url"]); + $this->log_debug("Download filename: " . $repo_data["download_info"]["filename"]); set_transient($cache_key, $repo_data, DAY_IN_SECONDS); - // 缓存头像(优先仓库头像) if (!empty($repo_data["repo_avatar_url"])) { $this->cache_avatar($repo_data["repo_avatar_url"]); } elseif (!empty($repo_data["owner"]["avatar_url"])) { @@ -329,6 +295,219 @@ class GitEmbedFeiCode return $repo_data; } + private function fetch_repository_info(array $api_config, string $owner, string $repo, string $platform): ?array + { + $url = $api_config["api_url"] . "/repos/{$owner}/{$repo}"; + + $this->log_debug("Fetching repo info from: {$url}"); + + $response = wp_remote_get($url, [ + "timeout" => 15, + "headers" => [ + "User-Agent" => "Git-Embed-FeiCode/" . self::PLUGIN_VERSION, + "Accept" => "application/json", + ], + ]); + + if (is_wp_error($response)) { + $this->log_debug("WP Error: " . $response->get_error_message()); + return null; + } + + $response_code = wp_remote_retrieve_response_code($response); + if ($response_code !== 200) { + $this->log_debug("HTTP {$response_code} error"); + return null; + } + + $data = json_decode(wp_remote_retrieve_body($response), true); + if (!$data) { + $this->log_debug("Failed to parse JSON response"); + return null; + } + + return $this->normalize_repository_data($data, $platform, $api_config); + } + + private function fetch_latest_release(array $api_config, string $owner, string $repo, string $platform): ?array + { + if ($platform === "gitlab") { + $releases_url = $api_config["api_url"] . "/projects/" . urlencode("{$owner}/{$repo}") . "/releases"; + } else { + $releases_url = $api_config["api_url"] . "/repos/{$owner}/{$repo}/releases/latest"; + } + + $this->log_debug("Fetching latest release from: {$releases_url}"); + + $response = wp_remote_get($releases_url, [ + "timeout" => 10, + "headers" => [ + "User-Agent" => "Git-Embed-FeiCode/" . self::PLUGIN_VERSION, + "Accept" => "application/json", + ], + ]); + + if (is_wp_error($response)) { + $this->log_debug("Release fetch error: " . $response->get_error_message()); + return null; + } + + $response_code = wp_remote_retrieve_response_code($response); + if ($response_code === 404) { + $this->log_debug("No releases found (404)"); + return null; + } + + if ($response_code !== 200) { + $this->log_debug("Release API returned {$response_code}"); + return null; + } + + $data = json_decode(wp_remote_retrieve_body($response), true); + if (!$data) { + return null; + } + + if ($platform === "gitlab") { + if (is_array($data) && !empty($data)) { + $latest = $data[0]; + return [ + "tag_name" => $latest["tag_name"], + "name" => $latest["name"] ?: $latest["tag_name"], + ]; + } + return null; + } + + if (isset($data["tag_name"])) { + return [ + "tag_name" => $data["tag_name"], + "name" => $data["name"] ?: $data["tag_name"], + "draft" => $data["draft"] ?? false, + ]; + } + + return null; + } + + private function generate_download_info( + string $platform, + array $api_config, + string $owner, + string $repo, + array $repo_data, + ?array $latest_release + ): array { + if ($latest_release && (!isset($latest_release["draft"]) || !$latest_release["draft"])) { + $tag_name = $latest_release["tag_name"]; + $this->log_debug("Using release {$tag_name} for download"); + + return [ + "type" => "release", + "version" => $tag_name, + "name" => $latest_release["name"] ?: $tag_name, + "url" => $this->build_archive_url($platform, $api_config, $owner, $repo, $tag_name, true), + "filename" => $this->generate_filename($repo_data["name"], $tag_name, true) + ]; + } + + $default_branch = $repo_data["default_branch"] ?: $this->detect_default_branch($api_config, $owner, $repo, $platform); + $this->log_debug("Using branch '{$default_branch}' for download"); + + return [ + "type" => "branch", + "version" => $default_branch, + "name" => __("Latest Code", self::TEXT_DOMAIN), + "url" => $this->build_archive_url($platform, $api_config, $owner, $repo, $default_branch, false), + "filename" => $this->generate_filename($repo_data["name"], $default_branch, false) + ]; + } + + private function build_archive_url( + string $platform, + array $api_config, + string $owner, + string $repo, + string $ref, + bool $is_release + ): string { + $base_url = $api_config["base_url"]; + $api_url = $api_config["api_url"]; + + switch ($platform) { + case "github": + $prefix = $is_release ? "refs/tags" : "refs/heads"; + return "https://github.com/{$owner}/{$repo}/archive/{$prefix}/{$ref}.zip"; + + case "gitlab": + return "{$base_url}/{$owner}/{$repo}/-/archive/{$ref}/{$repo}-{$ref}.zip"; + + case "gitea": + case "forgejo": + case "custom": + return "{$api_url}/repos/{$owner}/{$repo}/archive/{$ref}.zip"; + + default: + return ""; + } + } + + private function detect_default_branch(array $api_config, string $owner, string $repo, string $platform): string + { + $branches_url = $api_config["api_url"] . "/repos/{$owner}/{$repo}/branches"; + + $response = wp_remote_get($branches_url, [ + "timeout" => 10, + "headers" => [ + "User-Agent" => "Git-Embed-FeiCode/" . self::PLUGIN_VERSION, + "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)) { + foreach ($branches as $branch) { + if (isset($branch["name"]) && in_array($branch["name"], ["main", "master"])) { + return $branch["name"]; + } + } + if (isset($branches[0]["name"])) { + return $branches[0]["name"]; + } + } + } + + return "main"; + } + + private function generate_filename(string $repo_name, string $ref, bool $is_release): string + { + $safe_repo = preg_replace('/[^a-zA-Z0-9\-_.]/', '-', $repo_name); + + $clean_ref = $ref; + if (strpos($ref, 'refs/heads/') === 0) { + $clean_ref = substr($ref, 11); + } elseif (strpos($ref, 'refs/tags/') === 0) { + $clean_ref = substr($ref, 10); + } + + $safe_ref = preg_replace('/[^a-zA-Z0-9\-_.]/', '-', $clean_ref); + + if ($is_release) { + $safe_ref = preg_replace('/^v/', '', $safe_ref); + } + + return "{$safe_repo}-{$safe_ref}.zip"; + } + + private function log_debug(string $message): void + { + if (WP_DEBUG) { + error_log("Git Embed Debug: {$message}"); + } + } + private function get_api_config( string $platform, string $custom_domain = "", @@ -352,8 +531,7 @@ class GitEmbedFeiCode 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}", @@ -370,9 +548,7 @@ class GitEmbedFeiCode 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}", @@ -389,9 +565,7 @@ class GitEmbedFeiCode 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}", @@ -408,12 +582,7 @@ class GitEmbedFeiCode return null; } $domain = $this->normalize_domain($custom_domain); - $site_name = - $custom_site_name ?: - $this->get_site_name( - $domain, - __("Git Service", self::TEXT_DOMAIN), - ); + $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}", @@ -442,7 +611,7 @@ class GitEmbedFeiCode $response = wp_remote_get("https://{$domain}", [ "timeout" => 10, "headers" => [ - "User-Agent" => "Git-Embed-FeiCode/1.0", + "User-Agent" => "Git-Embed-FeiCode/" . self::PLUGIN_VERSION, ], ]); @@ -451,12 +620,8 @@ class GitEmbedFeiCode 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; @@ -468,67 +633,6 @@ class GitEmbedFeiCode return $fallback; } - 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/refs/heads/{$branch}.zip"; - $response = wp_remote_head($test_url, [ - "timeout" => 5, - "headers" => [ - "User-Agent" => "Git-Embed-FeiCode/1.0", - ], - ]); - - if ( - !is_wp_error($response) && - wp_remote_retrieve_response_code($response) === 200 - ) { - return $branch; - } - } - - return "main"; - } - private function normalize_domain(string $domain): string { $domain = trim($domain); @@ -537,19 +641,14 @@ class GitEmbedFeiCode return $domain; } - private function normalize_repository_data( - array $data, - string $platform, - array $api_config, - ): array { + 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"], + "full_name" => $data["path_with_namespace"] ?? ($data["namespace"]["name"] . "/" . $data["name"]), "description" => $data["description"], "html_url" => $data["web_url"], "language" => $data["language"] ?? null, @@ -557,89 +656,42 @@ class GitEmbedFeiCode "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", + "default_branch" => $data["default_branch"] ?? null, "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"), - ), + "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, ]; } - // GitHub, Gitea, Forgejo, Custom return [ "name" => $data["name"], - "full_name" => - $data["full_name"] ?? - $data["owner"]["login"] . "/" . $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), + "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), + "open_issues_count" => $data["open_issues_count"] ?? ($data["open_issues"] ?? 0), "clone_url" => $data["clone_url"], - "default_branch" => $data["default_branch"] ?? "main", + "default_branch" => $data["default_branch"] ?? null, "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", - ), + "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, ]; } - /** - * 简化的下载地址获取方法 - */ - private function get_simple_archive_url( - string $platform, - string $base_url, - string $owner, - string $repo, - string $branch, - ): string { - switch ($platform) { - 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 ""; - } - } - private function normalize_owner_type(string $type): string { $type = strtolower(trim($type)); @@ -670,7 +722,7 @@ class GitEmbedFeiCode $response = wp_remote_get($avatar_url, [ "timeout" => 10, "headers" => [ - "User-Agent" => "Git-Embed-FeiCode/1.0", + "User-Agent" => "Git-Embed-FeiCode/" . self::PLUGIN_VERSION, ], ]); @@ -682,29 +734,21 @@ class GitEmbedFeiCode } } - /** - * 获取显示用的头像 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 { + 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; @@ -723,44 +767,48 @@ class GitEmbedFeiCode $alignment = $attributes["alignment"] ?? "none"; $align_class = $alignment !== "none" ? " align{$alignment}" : ""; - $card_class = - $card_style !== "default" ? " git-embed-card-{$card_style}" : ""; + $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 = $repo_data["archive_url"]; - - // 获取显示用的头像(优先仓库头像) + $download_info = $repo_data["download_info"] ?? null; $display_avatar_url = $this->get_display_avatar_url($repo_data); + $download_url = ''; + $download_filename = ''; + $download_title = ''; + + if ($download_info) { + $download_url = $download_info["url"]; + $download_filename = $download_info["filename"]; + $download_title = sprintf( + __("Download %s (%s)", self::TEXT_DOMAIN), + $download_info["name"], + $download_info["version"] + ); + } elseif (!empty($repo_data["archive_url"])) { + $download_url = $repo_data["archive_url"]; + $download_filename = $repo_data["name"] . ".zip"; + $download_title = __("Download ZIP", self::TEXT_DOMAIN); + } + + $unique_id = 'git-embed-' . wp_generate_uuid4(); + ob_start(); ?> -
+
-
"> - " - alt="" +
"> + " + alt="" class="git-embed-site-favicon" loading="lazy" onerror="this.style.display='none'"> - " + " target="_blank" rel="noopener"> - +
@@ -769,66 +817,35 @@ class GitEmbedFeiCode -
- - - - + +
+ 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", self::TEXT_DOMAIN), - ); + wp_send_json_error(__("Failed to fetch repository", self::TEXT_DOMAIN)); } wp_send_json_success($repo_data); @@ -1094,9 +1063,7 @@ class GitEmbedFeiCode check_ajax_referer("git_embed_cache_nonce", "nonce"); if (!current_user_can("manage_options")) { - wp_send_json_error( - __("Insufficient permissions", self::TEXT_DOMAIN), - ); + wp_send_json_error(__("Insufficient permissions", self::TEXT_DOMAIN)); } $platform = sanitize_text_field($_POST["platform"] ?? ""); @@ -1106,22 +1073,12 @@ class GitEmbedFeiCode $repo = sanitize_text_field($_POST["repo"] ?? ""); if (empty($owner) || empty($repo)) { - wp_send_json_error( - __("Repository information required", self::TEXT_DOMAIN), - ); + wp_send_json_error(__("Repository information required", self::TEXT_DOMAIN)); } - $this->clear_repository_cache( - $platform, - $owner, - $repo, - $custom_domain, - $custom_site_name, - ); + $this->clear_repository_cache($platform, $owner, $repo, $custom_domain, $custom_site_name); - wp_send_json_success( - __("Cache cleared successfully", self::TEXT_DOMAIN), - ); + wp_send_json_success(__("Cache cleared successfully", self::TEXT_DOMAIN)); } private function clear_repository_cache( @@ -1131,8 +1088,7 @@ class GitEmbedFeiCode string $custom_domain = "", string $custom_site_name = "", ): void { - $cache_key = - "git_embed_{$platform}_{$owner}_{$repo}" . + $cache_key = "git_embed_{$platform}_{$owner}_{$repo}" . ($custom_domain ? "_{$custom_domain}" : "") . ($custom_site_name ? "_{$custom_site_name}" : ""); delete_transient($cache_key); @@ -1175,4 +1131,4 @@ class GitEmbedFeiCode } } -new GitEmbedFeiCode(); +new GitEmbedFeiCode(); \ No newline at end of file diff --git a/languages/git-embed-feicode-zh_CN.json b/languages/git-embed-feicode-zh_CN.json index 516acec..86c785c 100644 --- a/languages/git-embed-feicode-zh_CN.json +++ b/languages/git-embed-feicode-zh_CN.json @@ -13,24 +13,129 @@ "Embed a Git repository with information and stats": [ "嵌入包含信息和统计数据的 Git 仓库" ], + "Please enter repository owner and name": [ + "请输入仓库所有者和名称" + ], + "Please enter custom domain for": [ + "请输入自定义域名:" + ], + "Failed to fetch repository": [ + "获取仓库失败" + ], + "Network error occurred": [ + "网络错误" + ], + "Fetching repository data...": [ + "正在获取仓库数据..." + ], + "Git Repository Embed": [ + "Git 仓库嵌入" + ], + "Configure your repository details in the sidebar": [ + "在侧边栏配置您的仓库详情" + ], + "Download": [ + "下载" + ], + "Download ZIP": [ + "下载 ZIP" + ], + "Repository Avatar": [ + "仓库头像" + ], + "Owner Avatar": [ + "所有者头像" + ], + "Repository has custom avatar": [ + "仓库有自定义头像" + ], + "Stars:": [ + "星标:" + ], + "Forks:": [ + "分叉:" + ], + "Issues:": [ + "议题:" + ], + "View Repository": [ + "查看仓库" + ], + "Clone URL:": [ + "克隆链接:" + ], + "Clone": [ + "克隆" + ], + "Issues": [ + "议题" + ], + "Forks": [ + "分叉" + ], "Repository Settings": [ "仓库设置" ], "Platform": [ "平台" ], + "GitHub": [ + "GitHub" + ], + "Gitea": [ + "Gitea" + ], + "Forgejo": [ + "Forgejo" + ], + "GitLab (Self-hosted)": [ + "GitLab(自托管)" + ], + "Custom Git Service": [ + "自定义 Git 服务" + ], + "Self-hosted Git service requires custom domain": [ + "自托管 Git 服务需要自定义域名" + ], "Custom Domain": [ "自定义域名" ], + "e.g. git.example.com": [ + "例如:git.example.com" + ], + "Enter the domain of your": [ + "输入您的" + ], + "instance": [ + "实例域名" + ], "Custom Site Name (Optional)": [ "自定义站点名称(可选)" ], + "e.g. Company Git": [ + "例如:公司 Git" + ], + "Override the automatically detected site name": [ + "覆盖自动检测的站点名称" + ], "Repository Owner": [ "仓库所有者" ], + "e.g. facebook": [ + "例如:facebook" + ], "Repository Name": [ "仓库名称" ], + "e.g. react": [ + "例如:react" + ], + "Fetch Repository": [ + "获取仓库" + ], + "Fetching...": [ + "正在获取..." + ], "Display Options": [ "显示选项" ], @@ -40,9 +145,21 @@ "Show Avatar": [ "显示头像" ], + "Shows repository avatar if available, otherwise owner avatar": [ + "如果可用,显示仓库头像,否则显示所有者头像" + ], "Avatar Size": [ "头像大小" ], + "Small": [ + "小" + ], + "Medium": [ + "中" + ], + "Large": [ + "大" + ], "Show Description": [ "显示描述" ], @@ -76,75 +193,6 @@ "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": [ "默认" ], @@ -160,6 +208,15 @@ "Ghost": [ "幽灵" ], + "Button Size": [ + "按钮大小" + ], + "Style Options": [ + "样式选项" + ], + "Card Style": [ + "卡片样式" + ], "Minimal": [ "简约" ], @@ -174,6 +231,54 @@ ], "Glassmorphism": [ "玻璃态" + ], + "Repository information required": [ + "需要仓库信息" + ], + "Custom domain required for %s": [ + "%s 需要自定义域名" + ], + "Failed to fetch repository data": [ + "获取仓库数据失败" + ], + "Latest Code": [ + "最新代码" + ], + "Git Service": [ + "Git 服务" + ], + "Organization": [ + "组织" + ], + "User": [ + "用户" + ], + "Download %s (%s)": [ + "下载 %s (%s)" + ], + "Download %s": [ + "下载 %s" + ], + "Issues (%s)": [ + "议题 (%s)" + ], + "Forks (%s)": [ + "分叉 (%s)" + ], + "Click to copy clone URL": [ + "点击复制克隆链接" + ], + "Copied!": [ + "已复制!" + ], + "Please enter custom domain for %s": [ + "请输入 %s 的自定义域名" + ], + "Insufficient permissions": [ + "权限不足" + ], + "Cache cleared successfully": [ + "缓存清理成功" ] } } diff --git a/languages/git-embed-feicode-zh_CN.mo b/languages/git-embed-feicode-zh_CN.mo index a4ccdbb..eac0c83 100644 Binary files a/languages/git-embed-feicode-zh_CN.mo 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 index 9930d2d..9a65c23 100644 --- a/languages/git-embed-feicode-zh_CN.po +++ b/languages/git-embed-feicode-zh_CN.po @@ -7,7 +7,7 @@ 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" +"PO-Revision-Date: 2025-08-01 01:09+0800\n" "Last-Translator: feiCode Team\n" "Language-Team: Chinese (China)\n" "Language: zh_CN\n" @@ -200,6 +200,9 @@ msgstr "查看仓库" msgid "Clone" msgstr "克隆" +msgid "Download %s (%s)" +msgstr "下载 %s (%s)" + msgid "Download ZIP" msgstr "下载 ZIP" diff --git a/languages/git-embed-feicode-zh_CN.pot b/languages/git-embed-feicode-zh_CN.pot index 6ad0c21..3846530 100644 --- a/languages/git-embed-feicode-zh_CN.pot +++ b/languages/git-embed-feicode-zh_CN.pot @@ -1,141 +1,338 @@ # Copyright (C) 2024 feiCode # This file is distributed under the same license as the Git Embed for feiCode plugin. +#, fuzzy msgid "" msgstr "" -"Project-Id-Version: Git Embed for feiCode 1.0.1\n" +"Project-Id-Version: Git Embed for feiCode 1.0.2\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" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\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 - -" +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 +#: assets/block.js:15 msgid "Git Repository" msgstr "" -#: block.js:16 +#: assets/block.js:16 msgid "Embed a Git repository with information and stats" msgstr "" -#: block.js:170 +#: assets/block.js:85 +msgid "Please enter repository owner and name" +msgstr "" + +#: assets/block.js:89 +msgid "Please enter custom domain for" +msgstr "" + +#: assets/block.js:104 +msgid "Failed to fetch repository" +msgstr "" + +#: assets/block.js:109 +msgid "Network error occurred" +msgstr "" + +#: assets/block.js:127 +msgid "Fetching repository data..." +msgstr "" + +#: assets/block.js:140 +msgid "Git Repository Embed" +msgstr "" + +#: assets/block.js:141 +msgid "Configure your repository details in the sidebar" +msgstr "" + +#: assets/block.js:152 +msgid "Download" +msgstr "" + +#: assets/block.js:153 +msgid "Download ZIP" +msgstr "" + +#: assets/block.js:177 +msgid "Repository Avatar" +msgstr "" + +#: assets/block.js:177 +msgid "Owner Avatar" +msgstr "" + +#: assets/block.js:197 +msgid "Repository has custom avatar" +msgstr "" + +#: assets/block.js:217 +msgid "Stars:" +msgstr "" + +#: assets/block.js:221 +msgid "Forks:" +msgstr "" + +#: assets/block.js:225 +msgid "Issues:" +msgstr "" + +#: assets/block.js:237 +msgid "View Repository" +msgstr "" + +#: assets/block.js:241 +msgid "Clone URL:" +msgstr "" + +#: assets/block.js:244 +msgid "Clone" +msgstr "" + +#: assets/block.js:260 +msgid "Issues" +msgstr "" + +#: assets/block.js:268 +msgid "Forks" +msgstr "" + +#: assets/block.js:281 msgid "Repository Settings" msgstr "" -#: block.js:174 +#: assets/block.js:285 msgid "Platform" msgstr "" -#: block.js:185 +#: assets/block.js:287 +msgid "GitHub" +msgstr "" + +#: assets/block.js:288 +msgid "Gitea" +msgstr "" + +#: assets/block.js:289 +msgid "Forgejo" +msgstr "" + +#: assets/block.js:290 +msgid "GitLab (Self-hosted)" +msgstr "" + +#: assets/block.js:291 +msgid "Custom Git Service" +msgstr "" + +#: assets/block.js:294 +msgid "Self-hosted Git service requires custom domain" +msgstr "" + +#: assets/block.js:299 msgid "Custom Domain" msgstr "" -#: block.js:195 +#: assets/block.js:302 +msgid "e.g. git.example.com" +msgstr "" + +#: assets/block.js:303 +msgid "Enter the domain of your" +msgstr "" + +#: assets/block.js:303 +msgid "instance" +msgstr "" + +#: assets/block.js:308 msgid "Custom Site Name (Optional)" msgstr "" -#: block.js:205 +#: assets/block.js:311 +msgid "e.g. Company Git" +msgstr "" + +#: assets/block.js:312 +msgid "Override the automatically detected site name" +msgstr "" + +#: assets/block.js:317 msgid "Repository Owner" msgstr "" -#: block.js:214 +#: assets/block.js:320 +msgid "e.g. facebook" +msgstr "" + +#: assets/block.js:325 msgid "Repository Name" msgstr "" -#: block.js:227 +#: assets/block.js:328 +msgid "e.g. react" +msgstr "" + +#: assets/block.js:336 +msgid "Fetch Repository" +msgstr "" + +#: assets/block.js:336 +msgid "Fetching..." +msgstr "" + +#: assets/block.js:339 msgid "Display Options" msgstr "" -#: block.js:231 +#: assets/block.js:343 msgid "Show Site Information" msgstr "" -#: block.js:235 +#: assets/block.js:347 msgid "Show Avatar" msgstr "" -#: block.js:240 +#: assets/block.js:350 +msgid "Shows repository avatar if available, otherwise owner avatar" +msgstr "" + +#: assets/block.js:353 msgid "Avatar Size" msgstr "" -#: block.js:252 +#: assets/block.js:355 +msgid "Small" +msgstr "" + +#: assets/block.js:356 +msgid "Medium" +msgstr "" + +#: assets/block.js:357 +msgid "Large" +msgstr "" + +#: assets/block.js:364 msgid "Show Description" msgstr "" -#: block.js:256 +#: assets/block.js:368 msgid "Show Programming Language" msgstr "" -#: block.js:260 +#: assets/block.js:372 msgid "Show Statistics" msgstr "" -#: block.js:264 +#: assets/block.js:376 msgid "Show Action Buttons" msgstr "" -#: block.js:269 +#: assets/block.js:380 msgid "Button Options" msgstr "" -#: block.js:273 +#: assets/block.js:384 msgid "Show View Repository Button" msgstr "" -#: block.js:278 +#: assets/block.js:389 msgid "Show Clone Button" msgstr "" -#: block.js:283 +#: assets/block.js:394 msgid "Show Download ZIP Button" msgstr "" -#: block.js:288 +#: assets/block.js:399 msgid "Show Issues Button" msgstr "" -#: block.js:293 +#: assets/block.js:404 msgid "Show Forks Button" msgstr "" -#: block.js:298 +#: assets/block.js:409 msgid "Button Style" msgstr "" -#: block.js:312 +#: assets/block.js:411 +msgid "Default" +msgstr "" + +#: assets/block.js:412 +msgid "Primary (Green)" +msgstr "" + +#: assets/block.js:413 +msgid "Secondary (Gray)" +msgstr "" + +#: assets/block.js:414 +msgid "Outline" +msgstr "" + +#: assets/block.js:415 +msgid "Ghost" +msgstr "" + +#: assets/block.js:422 msgid "Button Size" msgstr "" -#: block.js:326 +#: assets/block.js:433 msgid "Style Options" msgstr "" -#: block.js:330 +#: assets/block.js:437 msgid "Card Style" msgstr "" +#: assets/block.js:440 +msgid "Minimal" +msgstr "" + +#: assets/block.js:441 +msgid "Bordered" +msgstr "" + +#: assets/block.js:442 +msgid "Shadow" +msgstr "" + +#: assets/block.js:443 +msgid "Gradient" +msgstr "" + +#: assets/block.js:444 +msgid "Glassmorphism" +msgstr "" + #: git-embed-feicode.php:85 msgid "Repository information required" msgstr "" #: git-embed-feicode.php:89 +#, php-format msgid "Custom domain required for %s" msgstr "" @@ -143,154 +340,75 @@ msgstr "" msgid "Failed to fetch repository data" msgstr "" -#: git-embed-feicode.php:672 -msgid "Insufficient permissions" +#: git-embed-feicode.php:246 +msgid "Latest Code" msgstr "" -#: git-embed-feicode.php:684 -msgid "Cache cleared successfully" +#: git-embed-feicode.php:429 +msgid "Git Service" 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 +#: git-embed-feicode.php:537 msgid "Organization" msgstr "" +#: git-embed-feicode.php:542 msgid "User" msgstr "" + +#: git-embed-feicode.php:617 +#, php-format +msgid "Download %s (%s)" +msgstr "" + +#: git-embed-feicode.php:625 +msgid "Download ZIP" +msgstr "" + +#: git-embed-feicode.php:679 +msgid "View Repository" +msgstr "" + +#: git-embed-feicode.php:687 +msgid "Clone" +msgstr "" + +#: git-embed-feicode.php:698 +#, php-format +msgid "Download %s" +msgstr "" + +#: git-embed-feicode.php:705 +#, php-format +msgid "Issues (%s)" +msgstr "" + +#: git-embed-feicode.php:714 +#, php-format +msgid "Forks (%s)" +msgstr "" + +#: git-embed-feicode.php:754 +msgid "Click to copy clone URL" +msgstr "" + +#: git-embed-feicode.php:798 +msgid "Copied!" +msgstr "" + +#: git-embed-feicode.php:816 +msgid "Please enter repository owner and name" +msgstr "" + +#: git-embed-feicode.php:820 +#, php-format +msgid "Please enter custom domain for %s" +msgstr "" + +#: git-embed-feicode.php:832 +msgid "Insufficient permissions" +msgstr "" + +#: git-embed-feicode.php:844 +msgid "Cache cleared successfully" +msgstr "" \ No newline at end of file diff --git a/languages/git-embed-feicode.pot b/languages/git-embed-feicode.pot new file mode 100644 index 0000000..eed3a82 --- /dev/null +++ b/languages/git-embed-feicode.pot @@ -0,0 +1,35 @@ +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Git Embed for feiCode\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-07-31 16:41+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: \n" +"Language: \n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Loco https://localise.biz/\n" +"X-Loco-Version: 2.8.0; wp-6.8.2; php-8.3.0-dev\n" +"X-Domain: git-embed-feicode" + +#. Description of the plugin +msgid "" +"Embed Git repositories from GitHub/Gitlab/Gitea/Forgejo and Self-hosted Git " +"service with beautiful cards" +msgstr "" + +#. Author of the plugin +msgid "feiCode" +msgstr "" + +#. Name of the plugin +msgid "Git Embed for feiCode" +msgstr "" + +#. Author URI of the plugin +msgid "https://cn.feicode.com" +msgstr ""