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();
?>
-
+
+ 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 ""