From 481cea3d1f8a2066b8dd64830caf4ee916f1d787 Mon Sep 17 00:00:00 2001 From: feibisi Date: Sun, 13 Jul 2025 03:11:45 +0800 Subject: [PATCH] Add initial WPSlug plugin files Introduce core plugin files including admin interface, conversion logic, settings, and supporting assets (CSS/JS). This sets up the main structure for slug conversion, optimization, and admin configuration. --- assets/admin.css | 541 ++++++++ assets/admin.js | 841 ++++++++++++ includes/class-wpslug-admin.php | 1489 ++++++++++++++++++++++ includes/class-wpslug-converter.php | 293 +++++ includes/class-wpslug-core.php | 393 ++++++ includes/class-wpslug-optimizer.php | 302 +++++ includes/class-wpslug-pinyin.php | 166 +++ includes/class-wpslug-settings.php | 705 ++++++++++ includes/class-wpslug-translator.php | 267 ++++ includes/class-wpslug-transliterator.php | 200 +++ includes/class-wpslug-validator.php | 193 +++ includes/dictionary.php | 419 ++++++ wpslug.php | 228 ++++ 13 files changed, 6037 insertions(+) create mode 100644 assets/admin.css create mode 100644 assets/admin.js create mode 100644 includes/class-wpslug-admin.php create mode 100644 includes/class-wpslug-converter.php create mode 100644 includes/class-wpslug-core.php create mode 100644 includes/class-wpslug-optimizer.php create mode 100644 includes/class-wpslug-pinyin.php create mode 100644 includes/class-wpslug-settings.php create mode 100644 includes/class-wpslug-translator.php create mode 100644 includes/class-wpslug-transliterator.php create mode 100644 includes/class-wpslug-validator.php create mode 100644 includes/dictionary.php create mode 100644 wpslug.php diff --git a/assets/admin.css b/assets/admin.css new file mode 100644 index 0000000..b9fb9da --- /dev/null +++ b/assets/admin.css @@ -0,0 +1,541 @@ +.wpslug-card { + background: #fff; + border: 1px solid #ccd0d4; + border-radius: 4px; + margin-top: 20px; + padding: 20px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); +} + +.wpslug-card h2 { + margin-top: 0; + margin-bottom: 15px; + color: #23282d; + font-size: 18px; + font-weight: 600; +} + +.wpslug-tabs { + display: flex; + flex-wrap: wrap; + gap: 5px; + border-bottom: 1px solid #c3c4c7; + margin-bottom: 20px; +} + +.wpslug-tab { + padding: 10px 16px; + border: none; + background: none; + cursor: pointer; + font-size: 14px; + border-bottom: 2px solid transparent; + transition: all 0.2s ease; +} + +.wpslug-tab.active { + border-bottom: 2px solid #007cba; + font-weight: 600; + background: #f0f0f1; + color: #007cba; +} + +.wpslug-tab:hover:not(.active) { + background: #f0f0f1; + border-bottom-color: #dcdcde; +} + +.wpslug-tab-content { + flex: 1; +} + +.wpslug-section { + display: none; +} + +.wpslug-section.active { + display: block; +} + +.wpslug-section-header { + margin-bottom: 20px; + padding-bottom: 15px; + border-bottom: 1px solid #e1e1e1; +} + +.wpslug-section-header h3 { + margin: 0 0 5px 0; + font-size: 16px; + color: #23282d; +} + +.wpslug-section-header p { + margin: 0; + color: #646970; + font-size: 14px; +} + +.wpslug-dependent { + opacity: 1; + transition: opacity 0.3s ease; +} + +.wpslug-dependent.disabled { + opacity: 0.5; + pointer-events: none; +} + +.wpslug-seo-dependent { + opacity: 1; + transition: opacity 0.3s ease; +} + +.wpslug-seo-dependent.disabled { + opacity: 0.5; + pointer-events: none; +} + +.wpslug-stopwords-dependent { + opacity: 1; + transition: opacity 0.3s ease; +} + +.wpslug-stopwords-dependent.disabled { + opacity: 0.5; + pointer-events: none; +} + +.wpslug-api-sections { + margin-top: 20px; +} + +.wpslug-api-section { + background: #f9f9f9; + border: 1px solid #e1e1e1; + border-radius: 4px; + padding: 15px; + margin-bottom: 15px; + display: none; +} + +.wpslug-api-section h4 { + margin-top: 0; + margin-bottom: 10px; + color: #23282d; + font-size: 14px; +} + +.wpslug-checkbox-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 10px; + margin-bottom: 10px; +} + +.wpslug-checkbox-item { + display: flex; + align-items: center; + padding: 8px; + background: #f8f9fa; + border: 1px solid #e9ecef; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.2s ease; +} + +.wpslug-checkbox-item:hover { + background: #e9ecef; +} + +.wpslug-checkbox-item input[type="checkbox"] { + margin-right: 8px; +} + +.wpslug-checkbox-item span { + font-size: 13px; + color: #23282d; +} + +.wpslug-preview-section { + background: #f8f9fa; + border: 1px solid #e9ecef; + border-radius: 4px; + padding: 20px; + margin-top: 15px; +} + +.wpslug-preview-input { + display: flex; + gap: 10px; + margin-bottom: 15px; +} + +.wpslug-preview-input input[type="text"] { + flex: 1; + padding: 2px 12px; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 14px; + transition: border-color 0.2s ease; +} + +.wpslug-preview-input input[type="text"]:focus { + border-color: #007cba; + outline: none; + box-shadow: 0 0 0 1px #007cba; +} + +.wpslug-preview-input input[type="text"].valid { + border-color: #28a745; +} + +.wpslug-preview-input input[type="text"].invalid { + border-color: #dc3545; +} + +.wpslug-preview-input .button { + min-width: 100px; +} + +#wpslug-preview-result { + background: #fff; + border: 1px solid #ddd; + border-radius: 4px; + padding: 15px; + min-height: 40px; + font-family: monospace; + font-size: 13px; + line-height: 1.6; +} + +#wpslug-preview-result .result-item { + margin-bottom: 8px; +} + +#wpslug-preview-result .result-item:last-child { + margin-bottom: 0; +} + +#wpslug-preview-result .result-label { + font-weight: 600; + color: #23282d; +} + +#wpslug-preview-result .result-value { + color: #007cba; + font-weight: 500; +} + +#wpslug-preview-result .result-final { + background: #d4edda; + color: #155724; + padding: 4px 8px; + border-radius: 3px; + font-weight: 600; +} + +#wpslug-preview-result .result-meta { + color: #6c757d; + font-size: 12px; + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid #e9ecef; +} + +.wpslug-notice { + padding: 12px 15px; + border-radius: 4px; + margin-bottom: 15px; + font-size: 14px; + border-left: 4px solid #ddd; + background: #fff; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); +} + +.wpslug-notice p { + margin: 0; + padding: 0; +} + +.wpslug-notice.notice-success { + background-color: #d4edda; + border-left-color: #28a745; + color: #155724; +} + +.wpslug-notice.notice-error { + background-color: #f8d7da; + border-left-color: #dc3545; + color: #721c24; +} + +.wpslug-notice.notice-info { + background-color: #cce7ff; + border-left-color: #007cba; + color: #004085; +} + +.wpslug-submit-section { + display: flex; + gap: 10px; + align-items: center; + justify-content: flex-start; + padding-top: 20px; + border-top: 1px solid #e1e1e1; + margin-top: 20px; +} + +.wpslug-test-api { + margin-left: 10px; + min-width: 80px; +} + +.form-table th { + width: 200px; + padding: 15px 10px 15px 0; + font-weight: 600; + vertical-align: top; +} + +.form-table td { + padding: 15px 10px; +} + +.form-table .description { + color: #646970; + font-size: 13px; + margin-top: 5px; + line-height: 1.5; +} + +.form-table .description a { + color: #007cba; + text-decoration: none; +} + +.form-table .description a:hover { + text-decoration: underline; +} + +.form-table input[type="text"], +.form-table input[type="number"], +.form-table select { + border: 1px solid #ddd; + border-radius: 4px; + font-size: 14px; + transition: border-color 0.2s ease; +} + +.form-table input[type="text"]:focus, +.form-table input[type="number"]:focus, +.form-table select:focus { + border-color: #007cba; + outline: none; + box-shadow: 0 0 0 1px #007cba; +} + +.form-table .regular-text { + width: 25em; +} + +.form-table .small-text { + width: 50px; +} + +.form-table .large-text { + width: 100%; + max-width: 500px; +} + +.form-table label { + display: block; + margin-bottom: 5px; + cursor: pointer; +} + +.form-table label input[type="checkbox"] { + margin-right: 5px; +} + +.form-table tr.disabled { + opacity: 0.5; + pointer-events: none; +} + +.wpslug-api-status { + display: inline-block; + padding: 2px 6px; + border-radius: 3px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + margin-left: 8px; +} + +.wpslug-api-status.connected { + background: #d4edda; + color: #155724; +} + +.wpslug-api-status.disconnected { + background: #f8d7da; + color: #721c24; +} + +.wpslug-slug { + background: #f1f1f1; + padding: 3px 8px; + border-radius: 3px; + font-family: monospace; + font-size: 12px; + color: #23282d; + display: inline-block; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.wpslug-na { + color: #666; + font-style: italic; + font-size: 12px; +} + +.wpslug-error { + color: #d63638; + font-weight: bold; + font-size: 12px; +} + +.wpslug-disable-section { + padding: 10px 0; + border-bottom: 1px solid #eee; +} + +.wpslug-disable-section label { + display: flex; + align-items: center; + cursor: pointer; + font-size: 13px; +} + +.wpslug-disable-section input[type="checkbox"] { + margin-right: 8px; +} + +.wpslug-loading-spinner { + display: inline-block; + padding: 10px; + color: #666; + position: relative; +} + +.wpslug-loading-spinner::after { + content: ""; + display: inline-block; + width: 16px; + height: 16px; + border: 2px solid #007cba; + border-radius: 50%; + border-top-color: transparent; + animation: spin 1s linear infinite; + margin-left: 8px; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +.seo-warning { + color: #d63384; + font-size: 12px; + margin-left: 5px; + font-style: italic; +} + +.pinyin-first-notice { + color: #d63384; + font-size: 12px; + margin-top: 5px; + font-style: italic; + display: block; +} + +@media (max-width: 782px) { + .wpslug-tabs { + flex-direction: column; + } + + .wpslug-tab { + border-bottom: 1px solid #e1e1e1; + border-radius: 0; + padding: 12px 16px; + text-align: left; + } + + .wpslug-tab.active { + border-bottom: 1px solid #007cba; + border-left: 3px solid #007cba; + } + + .wpslug-preview-input { + flex-direction: column; + } + + .wpslug-preview-input .button { + min-width: auto; + } + + .wpslug-checkbox-grid { + grid-template-columns: 1fr; + } + + .wpslug-submit-section { + flex-direction: column; + align-items: stretch; + } + + .wpslug-submit-section .button { + margin-bottom: 10px; + } + + .form-table th, + .form-table td { + display: block; + width: 100%; + padding: 10px 0; + } + + .form-table th { + border-bottom: none; + padding-bottom: 5px; + } + + .form-table .regular-text { + width: 100%; + } + + .form-table .large-text { + width: 100%; + } +} + +@media (max-width: 480px) { + .wpslug-card { + margin: 10px 0; + padding: 15px; + } + + .wpslug-section-header { + padding-bottom: 10px; + } + + .wpslug-preview-section { + padding: 15px; + } + + .wpslug-preview-input input[type="text"] { + font-size: 16px; + } +} \ No newline at end of file diff --git a/assets/admin.js b/assets/admin.js new file mode 100644 index 0000000..1f33624 --- /dev/null +++ b/assets/admin.js @@ -0,0 +1,841 @@ +jQuery(document).ready(function ($) { + function initTabSwitching() { + $(".wpslug-tab").on("click", function (e) { + e.preventDefault(); + var target = $(this).data("tab"); + + $(".wpslug-tab").removeClass("active"); + $(this).addClass("active"); + + $(".wpslug-section").removeClass("active"); + $('.wpslug-section[data-section="' + target + '"]').addClass("active"); + + $("#wpslug_current_tab").val(target); + }); + + if (wpslug_ajax.current_tab && wpslug_ajax.current_tab !== "general") { + $('.wpslug-tab[data-tab="' + wpslug_ajax.current_tab + '"]').click(); + } + } + + function initDependentFields() { + function toggleDependentFields() { + var enableConversion = $("#enable_conversion").is(":checked"); + + $(".wpslug-dependent").each(function () { + var $row = $(this); + var dependsOn = $row.data("depends"); + + if (dependsOn === "enable_conversion") { + if (enableConversion) { + $row.removeClass("disabled"); + $row.find("input, select").prop("disabled", false); + } else { + $row.addClass("disabled"); + $row.find("input, select").prop("disabled", true); + } + } + }); + } + + $("#enable_conversion").on("change", toggleDependentFields); + toggleDependentFields(); + } + + function initConversionModeToggle() { + function toggleModeBasedTabs() { + var selectedMode = $("#conversion_mode").val(); + + $(".wpslug-tab").each(function () { + var tabName = $(this).data("tab"); + var $tab = $(this); + + if ( + tabName === "pinyin" || + tabName === "transliteration" || + tabName === "translation" + ) { + if (tabName === selectedMode) { + $tab.show(); + } else { + $tab.hide(); + if ($tab.hasClass("active")) { + $tab.removeClass("active"); + $('.wpslug-tab[data-tab="general"]').addClass("active"); + $(".wpslug-section").removeClass("active"); + $('.wpslug-section[data-section="general"]').addClass("active"); + $("#wpslug_current_tab").val("general"); + } + } + } + }); + } + + $("#conversion_mode").on("change", function () { + toggleModeBasedTabs(); + updateTranslationServiceToggle(); + }); + toggleModeBasedTabs(); + } + + function updateTranslationServiceToggle() { + var conversionMode = $("#conversion_mode").val(); + var $translationService = $("#translation_service"); + + if ( + conversionMode === "translation" && + $translationService.val() === "none" + ) { + $translationService.val("google"); + $translationService.trigger("change"); + } + } + + function initTranslationServiceToggle() { + function toggleApiSections() { + var service = $("#translation_service").val(); + + $(".wpslug-api-section").hide(); + if (service && service !== "none") { + $('.wpslug-api-section[data-service="' + service + '"]').show(); + } + } + + $("#translation_service").on("change", toggleApiSections); + toggleApiSections(); + } + + function initSEOOptimizationToggle() { + function toggleSEOFeatures() { + var seoEnabled = $("#enable_seo_optimization").is(":checked"); + var pinyinFormat = $("#pinyin_format").val(); + var conversionMode = $("#conversion_mode").val(); + var removeStopWords = $("#remove_stop_words").is(":checked"); + + var isFirstLetterMode = + conversionMode === "pinyin" && pinyinFormat === "first"; + var shouldDisableSEO = !seoEnabled || isFirstLetterMode; + + var $seoOptions = $( + ".wpslug-seo-dependent input, .wpslug-seo-dependent select, .wpslug-seo-dependent textarea", + ); + var $seoOptimizationCheckbox = $("#enable_seo_optimization"); + var $stopWordsOptions = $( + ".wpslug-stopwords-dependent input, .wpslug-stopwords-dependent select, .wpslug-stopwords-dependent textarea", + ); + + if (isFirstLetterMode) { + $seoOptimizationCheckbox.prop("disabled", true).prop("checked", false); + $(".wpslug-seo-dependent").addClass("disabled"); + $seoOptions.prop("disabled", true); + + if ($(".pinyin-first-notice").length === 0) { + $seoOptimizationCheckbox + .closest("td") + .append( + '
SEO optimization is automatically disabled in first letter mode for maximum brevity.
', + ); + } + } else { + $seoOptimizationCheckbox.prop("disabled", false); + $(".pinyin-first-notice").remove(); + + if (seoEnabled) { + $(".wpslug-seo-dependent").removeClass("disabled"); + $seoOptions.prop("disabled", false); + + if (removeStopWords) { + $(".wpslug-stopwords-dependent").removeClass("disabled"); + $stopWordsOptions.prop("disabled", false); + } else { + $(".wpslug-stopwords-dependent").addClass("disabled"); + $stopWordsOptions.prop("disabled", true); + } + } else { + $(".wpslug-seo-dependent").addClass("disabled"); + $seoOptions.prop("disabled", true); + } + } + } + + $(document).on("change", "#enable_seo_optimization", toggleSEOFeatures); + $(document).on("change", "#remove_stop_words", toggleSEOFeatures); + $("#pinyin_format").on("change", toggleSEOFeatures); + $("#conversion_mode").on("change", toggleSEOFeatures); + toggleSEOFeatures(); + } + + function initPreviewFunctionality() { + function performPreview() { + var text = $("#wpslug-preview-input").val().trim(); + var $button = $("#wpslug-preview-button"); + var $result = $("#wpslug-preview-result"); + + if (!text) { + showNotice("error", wpslug_ajax.strings.no_text); + return; + } + + $button.prop("disabled", true).text(wpslug_ajax.strings.converting); + $result.html('
Converting...
'); + + $.ajax({ + url: wpslug_ajax.ajax_url, + type: "POST", + data: { + action: "wpslug_preview", + text: text, + nonce: wpslug_ajax.nonce, + }, + success: function (response) { + if (response.success) { + var data = response.data; + var html = buildPreviewResult(data); + $result.html(html); + hideNotice(); + } else { + showNotice( + "error", + response.data.message || wpslug_ajax.strings.conversion_error, + ); + $result.html('
Preview failed
'); + } + }, + error: function () { + showNotice("error", wpslug_ajax.strings.conversion_error); + $result.html('
Connection error
'); + }, + complete: function () { + $button.prop("disabled", false).text(wpslug_ajax.strings.preview); + }, + }); + } + + function buildPreviewResult(data) { + var html = '
'; + html += 'Original: '; + html += + '' + escapeHtml(data.original) + ""; + html += "
"; + + if (data.converted && data.converted !== data.original) { + html += '
'; + html += 'Converted: '; + html += + '' + + escapeHtml(data.converted) + + ""; + html += "
"; + } + + if (data.optimized && data.optimized !== data.converted) { + html += '
'; + html += 'Optimized: '; + html += + '' + + escapeHtml(data.optimized) + + ""; + html += "
"; + } + + html += '
'; + html += 'Final Slug: '; + html += + '' + escapeHtml(data.final) + ""; + html += "
"; + + html += '
'; + html += "Mode: " + escapeHtml(data.mode); + if (data.detected_language) { + html += " | Detected: " + escapeHtml(data.detected_language); + } + html += "
"; + + return html; + } + + $("#wpslug-preview-button").on("click", performPreview); + $("#wpslug-preview-input").on("keypress", function (e) { + if (e.which === 13) { + performPreview(); + } + }); + } + + function initApiTesting() { + $(".wpslug-test-api").on("click", function () { + var $button = $(this); + var service = $button.data("service"); + var originalText = $button.text(); + + if (service === "google") { + var apiKey = $('input[name="wpslug_options[google_api_key]"]') + .val() + .trim(); + if (!apiKey) { + showNotice("error", "Google API key is required for testing."); + return; + } + } else if (service === "baidu") { + var appId = $('input[name="wpslug_options[baidu_app_id]"]') + .val() + .trim(); + var secretKey = $('input[name="wpslug_options[baidu_secret_key]"]') + .val() + .trim(); + if (!appId || !secretKey) { + showNotice( + "error", + "Both Baidu App ID and Secret Key are required for testing.", + ); + return; + } + } + + $button.prop("disabled", true).text(wpslug_ajax.strings.testing); + + $.ajax({ + url: wpslug_ajax.ajax_url, + type: "POST", + data: { + action: "wpslug_test_api", + service: service, + nonce: wpslug_ajax.nonce, + }, + success: function (response) { + if (response.success) { + showNotice( + "success", + response.data.message || wpslug_ajax.strings.api_test_success, + ); + $button.after( + 'Connected', + ); + } else { + showNotice( + "error", + response.data.message || wpslug_ajax.strings.api_test_failed, + ); + $button.after( + 'Failed', + ); + } + }, + error: function () { + showNotice("error", wpslug_ajax.strings.api_test_failed); + $button.after( + 'Error', + ); + }, + complete: function () { + $button.prop("disabled", false).text(originalText); + setTimeout(function () { + $(".wpslug-api-status").fadeOut(function () { + $(this).remove(); + }); + }, 3000); + }, + }); + }); + } + + function initResetSettings() { + $("#wpslug-reset-settings").on("click", function () { + if (confirm(wpslug_ajax.strings.reset_confirm)) { + showNotice("info", "Resetting settings to defaults..."); + + setTimeout(function () { + var $form = $("#wpslug-settings-form"); + + $form.find('input[type="checkbox"]').prop("checked", false); + $form.find('input[type="text"], input[type="number"]').val(""); + $form.find("select").prop("selectedIndex", 0); + $form.find("textarea").val(""); + + $("#enable_conversion").prop("checked", true); + $('input[name="wpslug_options[auto_convert]"]').prop("checked", true); + $('input[name="wpslug_options[force_lowercase]"]').prop( + "checked", + true, + ); + $('input[name="wpslug_options[preserve_english]"]').prop( + "checked", + true, + ); + $('input[name="wpslug_options[preserve_numbers]"]').prop( + "checked", + true, + ); + $('input[name="wpslug_options[preserve_media_extension]"]').prop( + "checked", + true, + ); + $('input[name="wpslug_options[enable_seo_optimization]"]').prop( + "checked", + true, + ); + $('input[name="wpslug_options[smart_punctuation]"]').prop( + "checked", + true, + ); + $('input[name="wpslug_options[mixed_content_optimization]"]').prop( + "checked", + true, + ); + $('input[name="wpslug_options[remove_stop_words]"]').prop( + "checked", + true, + ); + + $('input[name="wpslug_options[max_length]"]').val("100"); + $('input[name="wpslug_options[seo_max_words]"]').val("5"); + + $("#conversion_mode").val("pinyin"); + $("#translation_service").val("none"); + $('select[name="wpslug_options[pinyin_separator]"]').val("-"); + $('select[name="wpslug_options[pinyin_format]"]').val("full"); + $('select[name="wpslug_options[transliteration_method]"]').val( + "basic", + ); + $('select[name="wpslug_options[translation_source_lang]"]').val( + "auto", + ); + $('select[name="wpslug_options[translation_target_lang]"]').val("en"); + $('select[name="wpslug_options[media_conversion_mode]"]').val( + "normal", + ); + + $('input[name="wpslug_options[enabled_post_types][]"]').prop( + "checked", + false, + ); + $( + 'input[name="wpslug_options[enabled_post_types][]"][value="post"]', + ).prop("checked", true); + $( + 'input[name="wpslug_options[enabled_post_types][]"][value="page"]', + ).prop("checked", true); + + $('input[name="wpslug_options[enabled_taxonomies][]"]').prop( + "checked", + false, + ); + $( + 'input[name="wpslug_options[enabled_taxonomies][]"][value="category"]', + ).prop("checked", true); + $( + 'input[name="wpslug_options[enabled_taxonomies][]"][value="post_tag"]', + ).prop("checked", true); + + $("#stop_words_list").val( + "the,a,an,and,or,but,in,on,at,to,for,of,with,by,from,up,about,into,through,during,before,after,above,below,between,among,since,without,within", + ); + + $("#enable_conversion").trigger("change"); + $("#conversion_mode").trigger("change"); + $("#enable_seo_optimization").trigger("change"); + $("#remove_stop_words").trigger("change"); + $("#pinyin_format").trigger("change"); + $("#translation_service").trigger("change"); + + showNotice( + "success", + "Settings reset to defaults. Remember to save your changes.", + ); + }, 100); + } + }); + } + + function initFormValidation() { + $("#wpslug-settings-form").on("submit", function (e) { + var hasError = false; + + console.log("WP Slug - Form submission started"); + + var checkboxes = $('input[type="checkbox"]'); + checkboxes.each(function () { + var $this = $(this); + var name = $this.attr("name"); + var checked = $this.is(":checked"); + var value = $this.val(); + + console.log( + " Checkbox " + name + ": checked=" + checked + ", value=" + value, + ); + }); + + var conversionMode = $("#conversion_mode").val(); + if (conversionMode === "translation") { + var translationService = $("#translation_service").val(); + if (translationService === "google") { + var apiKey = $('input[name="wpslug_options[google_api_key]"]') + .val() + .trim(); + if (!apiKey) { + showNotice( + "error", + "Google API key is required when using Google Translate service.", + ); + hasError = true; + } + } else if (translationService === "baidu") { + var appId = $('input[name="wpslug_options[baidu_app_id]"]') + .val() + .trim(); + var secretKey = $('input[name="wpslug_options[baidu_secret_key]"]') + .val() + .trim(); + if (!appId || !secretKey) { + showNotice( + "error", + "Both Baidu App ID and Secret Key are required when using Baidu Translate service.", + ); + hasError = true; + } + } + } + + var maxLength = parseInt( + $('input[name="wpslug_options[max_length]"]').val(), + ); + if (maxLength && (maxLength < 0 || maxLength > 500)) { + showNotice("error", "Maximum length must be between 0 and 500."); + hasError = true; + } + + var seoMaxWords = parseInt( + $('input[name="wpslug_options[seo_max_words]"]').val(), + ); + if (seoMaxWords && (seoMaxWords < 1 || seoMaxWords > 30)) { + showNotice("error", "SEO maximum words must be between 1 and 30."); + hasError = true; + } + + var enableSEO = $("#enable_seo_optimization").is(":checked"); + var removeStopWords = $("#remove_stop_words").is(":checked"); + var stopWordsList = $("#stop_words_list").val().trim(); + + if (enableSEO && removeStopWords && stopWordsList === "") { + showNotice( + "error", + 'Stop words list cannot be empty when "Remove Stop Words" is enabled.', + ); + hasError = true; + } + + if (hasError) { + e.preventDefault(); + $("html, body").animate( + { + scrollTop: 0, + }, + 500, + ); + return false; + } + + console.log("WP Slug - Form validation passed"); + hideNotice(); + }); + } + + function initAdvancedFeatures() { + $(".wpslug-checkbox-item").on("click", function (e) { + if ($(e.target).is('input[type="checkbox"]')) { + return; + } + + var $checkbox = $(this).find('input[type="checkbox"]'); + if (!$checkbox.is(":disabled")) { + $checkbox.prop("checked", !$checkbox.prop("checked")); + } + }); + + $('.wpslug-checkbox-item input[type="checkbox"]').on("click", function (e) { + e.stopPropagation(); + }); + + $("#wpslug-debug-checkboxes").on("click", function () { + var checkboxData = {}; + var hiddenData = {}; + + $('input[type="checkbox"]').each(function () { + var $this = $(this); + var name = $this.attr("name"); + var checked = $this.is(":checked"); + var value = $this.val(); + + checkboxData[name] = { + checked: checked, + value: value, + }; + }); + + $('input[type="hidden"]').each(function () { + var $this = $(this); + var name = $this.attr("name"); + var value = $this.val(); + + if (name && name.indexOf("wpslug_options") !== -1) { + hiddenData[name] = value; + } + }); + + console.log("WP Slug Debug - Checkbox states:", checkboxData); + console.log("WP Slug Debug - Hidden field states:", hiddenData); + + alert( + "Debug information logged to console. Check browser developer tools.", + ); + }); + + $("#wpslug-test-form-data").on("click", function () { + var formData = new FormData($("#wpslug-settings-form")[0]); + var formObject = {}; + + for (var pair of formData.entries()) { + if (formObject[pair[0]]) { + if (Array.isArray(formObject[pair[0]])) { + formObject[pair[0]].push(pair[1]); + } else { + formObject[pair[0]] = [formObject[pair[0]], pair[1]]; + } + } else { + formObject[pair[0]] = pair[1]; + } + } + + console.log( + "WP Slug Debug - Form data that would be submitted:", + formObject, + ); + + var wpslugOptions = {}; + Object.keys(formObject).forEach(function (key) { + if (key.startsWith("wpslug_options[")) { + var optionKey = key.replace("wpslug_options[", "").replace("]", ""); + wpslugOptions[optionKey] = formObject[key]; + } + }); + + console.log( + "WP Slug Debug - WPSlug options that would be submitted:", + wpslugOptions, + ); + + alert( + "Form data information logged to console. Check browser developer tools.", + ); + }); + } + + function initKeyboardShortcuts() { + $(document).on("keydown", function (e) { + if (e.ctrlKey || e.metaKey) { + switch (e.which) { + case 13: + if ($("#wpslug-preview-input").is(":focus")) { + e.preventDefault(); + $("#wpslug-preview-button").click(); + } + break; + case 83: + if ($("#wpslug-settings-form").length) { + e.preventDefault(); + $("#wpslug-settings-form").submit(); + } + break; + } + } + }); + } + + function initResponsiveEnhancements() { + function checkWindowSize() { + var $tabs = $(".wpslug-tabs"); + + if ($(window).width() < 782) { + $tabs.addClass("mobile-view"); + } else { + $tabs.removeClass("mobile-view"); + } + } + + $(window).on("resize", checkWindowSize); + checkWindowSize(); + } + + function initSmartDefaults() { + $("#remove_stop_words").on("change", function () { + var isChecked = $(this).is(":checked"); + var $stopWordsList = $("#stop_words_list"); + + if (isChecked && $stopWordsList.val().trim() === "") { + $stopWordsList.val( + "the,a,an,and,or,but,in,on,at,to,for,of,with,by,from,up,about,into,through,during,before,after,above,below,between,among,since,without,within", + ); + } + }); + } + + function initSEOFeatures() { + var $previewInput = $("#wpslug-preview-input"); + var $previewResult = $("#wpslug-preview-result"); + + $previewInput.on("input", function () { + var text = $(this).val().trim(); + if (text.length > 0) { + $(this).removeClass("invalid").addClass("valid"); + } else { + $(this).removeClass("valid invalid"); + } + }); + + $('input[name="wpslug_options[seo_max_words]"]').on("input", function () { + var value = parseInt($(this).val()); + var $warning = $(this).siblings(".seo-warning"); + + if (value > 10) { + if ($warning.length === 0) { + $(this).after( + 'High word count may impact SEO', + ); + } + } else { + $warning.remove(); + } + }); + } + + function initMediaSettings() { + function toggleMediaSettings() { + var mediaDisabled = $( + 'input[name="wpslug_options[disable_file_convert]"]', + ).is(":checked"); + var $mediaOptions = $( + 'select[name="wpslug_options[media_conversion_mode]"], input[name="wpslug_options[media_file_prefix]"], input[name="wpslug_options[preserve_media_extension]"]', + ); + + if (mediaDisabled) { + $mediaOptions.prop("disabled", true).closest("tr").addClass("disabled"); + } else { + $mediaOptions + .prop("disabled", false) + .closest("tr") + .removeClass("disabled"); + } + } + + $('input[name="wpslug_options[disable_file_convert]"]').on( + "change", + toggleMediaSettings, + ); + toggleMediaSettings(); + } + + function showNotice(type, message) { + var $notice = $("#wpslug-status"); + $notice + .removeClass("notice-success notice-error notice-info") + .addClass("notice-" + type) + .html("

" + escapeHtml(message) + "

") + .show(); + + if (type === "success") { + setTimeout(function () { + hideNotice(); + }, 5000); + } + + $("html, body").animate( + { + scrollTop: 0, + }, + 300, + ); + + console.log("WP Slug Notice: " + type + " - " + message); + } + + function hideNotice() { + $("#wpslug-status").fadeOut(); + } + + function escapeHtml(text) { + var map = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + }; + return text.replace(/[&<>"']/g, function (m) { + return map[m]; + }); + } + + function debugCheckboxStates() { + var checkboxes = $('input[type="checkbox"]'); + console.log("WP Slug - Checkbox states on page load:"); + + checkboxes.each(function () { + var $this = $(this); + var name = $this.attr("name"); + var checked = $this.is(":checked"); + var value = $this.val(); + + console.log(" " + name + ": checked=" + checked + ", value=" + value); + }); + } + + initTabSwitching(); + initDependentFields(); + initConversionModeToggle(); + initTranslationServiceToggle(); + initSEOOptimizationToggle(); + initPreviewFunctionality(); + initApiTesting(); + initResetSettings(); + initFormValidation(); + initAdvancedFeatures(); + initKeyboardShortcuts(); + initResponsiveEnhancements(); + initSmartDefaults(); + initSEOFeatures(); + initMediaSettings(); + + $(".settings-error.notice-success").hide(); + + debugCheckboxStates(); + + $(window).on("load", function () { + hideNotice(); + $(".settings-error.notice-success").hide(); + + if (window.location.search.indexOf("settings-updated=true") !== -1) { + console.log( + "WP Slug - Settings were just updated, checking current values...", + ); + + setTimeout(function () { + var checkboxes = $('input[type="checkbox"]'); + checkboxes.each(function () { + var $this = $(this); + var name = $this.attr("name"); + var checked = $this.is(":checked"); + var value = $this.val(); + + console.log( + " Post-save checkbox " + + name + + ": checked=" + + checked + + ", value=" + + value, + ); + }); + }, 1000); + } + }); +}); diff --git a/includes/class-wpslug-admin.php b/includes/class-wpslug-admin.php new file mode 100644 index 0000000..fd192ed --- /dev/null +++ b/includes/class-wpslug-admin.php @@ -0,0 +1,1489 @@ +settings = new WPSlug_Settings(); + $this->converter = new WPSlug_Converter(); + $this->optimizer = new WPSlug_Optimizer(); + + add_action("admin_menu", [$this, "addAdminMenu"]); + add_action("admin_init", [$this, "registerSettings"]); + add_action("admin_enqueue_scripts", [$this, "enqueueScripts"]); + add_action("admin_notices", [$this, "showAdminNotices"]); + add_action("wp_ajax_wpslug_preview", [$this, "ajaxPreview"]); + add_action("wp_ajax_wpslug_test_api", [$this, "ajaxTestApi"]); + add_action("post_submitbox_start", [$this, "addPostMetaBox"]); + add_filter("bulk_actions-edit-post", [$this, "addBulkAction"]); + add_filter("bulk_actions-edit-page", [$this, "addBulkAction"]); + add_filter( + "handle_bulk_actions-edit-post", + [$this, "handleBulkAction"], + 10, + 3 + ); + add_filter( + "handle_bulk_actions-edit-page", + [$this, "handleBulkAction"], + 10, + 3 + ); + add_action("admin_notices", [$this, "bulkActionNotice"]); + add_action("load-options-permalink.php", [$this, "addPermalinkNotice"]); + + add_action("admin_head", [$this, "hideDefaultNotices"]); + } + + public function hideDefaultNotices() + { + if (isset($_GET["page"]) && $_GET["page"] == "wpslug") { + echo ""; + } + } + + public function addAdminMenu() + { + add_options_page( + __("WPSlug Settings", "wpslug"), + __("Slug", "wpslug"), + "manage_options", + "wpslug", + [$this, "displayAdminPage"] + ); + } + + public function registerSettings() + { + register_setting("wpslug_settings", "wpslug_options", [ + "type" => "array", + "sanitize_callback" => [$this, "validateOptions"], + "default" => [], + "show_in_rest" => false, + ]); + + add_filter("wp_redirect", [$this, "preventDefaultNotice"], 10, 2); + } + + public function preventDefaultNotice($location, $status) + { + if (strpos($location, "options-general.php?page=wpslug") !== false) { + if (strpos($location, "settings-updated=true") !== false) { + return $location; + } + } + return $location; + } + + public function showAdminNotices() + { + if (isset($_GET["page"]) && $_GET["page"] == "wpslug") { + if ( + isset($_GET["settings-updated"]) && + $_GET["settings-updated"] == "true" + ) { + $message = __("Settings saved successfully!", "wpslug"); + echo '

' . + esc_html($message) . + "

"; + } + + if (isset($_GET["wpslug-error"])) { + $error_message = sanitize_text_field($_GET["wpslug-error"]); + echo '

' . + esc_html($error_message) . + "

"; + } + } + } + + public function displayAdminPage() + { + if (!current_user_can("manage_options")) { + wp_die( + __( + "You do not have sufficient permissions to access this page.", + "wpslug" + ) + ); + } + + $options = $this->settings->getOptions(); + $current_tab = isset($_GET["tab"]) + ? sanitize_text_field($_GET["tab"]) + : "general"; + ?> +
+ +

+ + + + + + + + + +

+ + +
+ + + +
+

+
+ + + + + + + +
+ +
+
" data-section="general"> + renderGeneralSettings($options); ?> +
+ +
" data-section="pinyin"> + renderPinyinSettings($options); ?> +
+ +
" data-section="transliteration"> + renderTransliterationSettings( + $options + ); ?> +
+ +
" data-section="translation"> + renderTranslationSettings($options); ?> +
+ +
" data-section="seo"> + renderSEOSettings($options); ?> +
+ +
" data-section="media"> + renderMediaSettings($options); ?> +
+ +
" data-section="advanced"> + renderAdvancedSettings($options); ?> +
+
+ +
+ + + + + +
+
+
+ +
+

+ +

+
+
+ " /> + +
+
+
+
+ +
+ +
+

+

+
+ + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

+ +

+
+ + +
+ + +
+ " + min="0" + max="500" + class="small-text"> +

+ +

+
+ +
+

+

+
+ + + + + + + + + + + + + + +
+ +

+ +

+
+ +

+ +

+
+ +
+ + +

+ +

+
+ +
+

+

+
+ + + + + + +
+ +

+ +

+
+ +
+

+

+
+ + + + + + + + + + + + + + +
+ +

+ +

+
+ +

+ +

+
+ +

+ +

+
+ +
+
+

+ + + + + +
+ " + class="regular-text"> + +

+ + + + +

+
+
+ +
+

+ + + + + + + + + +
+ " + class="regular-text"> +

+ +

+
+ " + class="regular-text"> + +

+ + + + +

+
+
+
+ +
+

+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +

+ +

+
+ + +

+ +

+
+ + +

+ +

+
+ + +

+ +

+
+ " + min="1" + max="30" + class="small-text"> +

+ +

+
+ +

+ +

+
+ +
+

+

+
+ + + + + + + + + + + + + + + + + + +
+ + +

+ +

+
+ +

+ +

+
+ " + class="regular-text"> +

+ +

+
+ + +

+ +

+
+ +
+

+

+
+ + + + + + + + + + +
+

+
+ true], + "objects" + ); + foreach ($post_types as $post_type) { + $checked = + is_array($options["enabled_post_types"]) && + in_array( + $post_type->name, + $options["enabled_post_types"] + ) + ? "checked" + : ""; ?> + + +
+

+ +

+ +

+
+ true], + "objects" + ); + foreach ($taxonomies as $taxonomy) { + $checked = + is_array($options["enabled_taxonomies"]) && + in_array( + $taxonomy->name, + $options["enabled_taxonomies"] + ) + ? "checked" + : ""; ?> + + +
+

+ +

+
+ + +
+ id !== "options-permalink") { + return; + } + + $options = $this->settings->getOptions(); + if (!$options["enable_conversion"]) { + return; + } + ?> +
+

+ - + + " class="button button-small" style="margin-left: 10px;"> + + +

+
+ settings->validateOptions($input); + + if (defined("WP_DEBUG") && WP_DEBUG) { + error_log( + "WP Slug - Validated data: " . + json_encode($validated, JSON_PRETTY_PRINT) + ); + } + + if (!empty($validated)) { + $current_options = $this->settings->getOptions(); + $merged_options = array_merge($current_options, $validated); + + if (defined("WP_DEBUG") && WP_DEBUG) { + error_log( + "WP Slug - Final merged options: " . + json_encode($merged_options, JSON_PRETTY_PRINT) + ); + } + + if ( + isset($_POST["wpslug_current_tab"]) && + !empty($_POST["wpslug_current_tab"]) + ) { + $tab = sanitize_text_field($_POST["wpslug_current_tab"]); + set_transient("wpslug_admin_tab", $tab, 60); + } + + return $merged_options; + } + + return $input; + } + + public function enqueueScripts($hook) + { + if ("settings_page_wpslug" !== $hook) { + return; + } + + wp_enqueue_script( + "wpslug-admin", + WPSLUG_PLUGIN_URL . "assets/admin.js", + ["jquery"], + WPSLUG_VERSION, + true + ); + wp_enqueue_style( + "wpslug-admin", + WPSLUG_PLUGIN_URL . "assets/admin.css", + [], + WPSLUG_VERSION + ); + + $saved_tab = get_transient("wpslug_admin_tab"); + if ($saved_tab) { + delete_transient("wpslug_admin_tab"); + } + + wp_localize_script("wpslug-admin", "wpslug_ajax", [ + "ajax_url" => admin_url("admin-ajax.php"), + "nonce" => wp_create_nonce("wpslug_nonce"), + "current_tab" => $saved_tab ?: "general", + "strings" => [ + "preview" => __("Preview", "wpslug"), + "converting" => __("Converting...", "wpslug"), + "testing" => __("Testing...", "wpslug"), + "test_api" => __("Test API", "wpslug"), + "reset_confirm" => __( + "Are you sure you want to reset all settings to default values?", + "wpslug" + ), + "api_test_success" => __( + "API connection successful!", + "wpslug" + ), + "api_test_failed" => __( + "API connection failed. Please check your credentials.", + "wpslug" + ), + "no_text" => __("Please enter some text to preview.", "wpslug"), + "conversion_error" => __( + "Conversion failed. Please check your settings.", + "wpslug" + ), + ], + ]); + } + + public function ajaxPreview() + { + check_ajax_referer("wpslug_nonce", "nonce"); + + $text = sanitize_text_field($_POST["text"]); + $options = $this->settings->getOptions(); + + if (empty($text)) { + wp_send_json_error([ + "message" => __("Please enter some text to preview.", "wpslug"), + ]); + } + + try { + $converted = $this->converter->convert($text, $options); + $optimized = $this->optimizer->optimize($converted, $options); + + wp_send_json_success([ + "original" => $text, + "converted" => $converted, + "optimized" => $optimized, + "final" => $optimized, + "mode" => $options["conversion_mode"], + "detected_language" => $this->converter->detectLanguage($text), + ]); + } catch (Exception $e) { + wp_send_json_error([ + "message" => __( + "Conversion failed. Please check your settings.", + "wpslug" + ), + ]); + } + } + + public function ajaxTestApi() + { + check_ajax_referer("wpslug_nonce", "nonce"); + + $service = sanitize_text_field($_POST["service"]); + $options = $this->settings->getOptions(); + + if ($service === "google") { + $api_key = trim($options["google_api_key"]); + if (empty($api_key)) { + wp_send_json_error([ + "message" => __( + "Google API key is required for testing.", + "wpslug" + ), + ]); + return; + } + } elseif ($service === "baidu") { + $app_id = trim($options["baidu_app_id"]); + $secret_key = trim($options["baidu_secret_key"]); + if (empty($app_id) || empty($secret_key)) { + wp_send_json_error([ + "message" => __( + "Both Baidu App ID and Secret Key are required for testing.", + "wpslug" + ), + ]); + return; + } + } else { + wp_send_json_error([ + "message" => __("Invalid service selected.", "wpslug"), + ]); + return; + } + + $test_text = "Hello World"; + $translator = new WPSlug_Translator(); + + try { + $result = $translator->translate( + $test_text, + array_merge($options, ["translation_service" => $service]) + ); + + if (!empty($result) && $result !== $test_text) { + wp_send_json_success([ + "message" => __("API connection successful!", "wpslug"), + ]); + } else { + wp_send_json_error([ + "message" => __( + "API connection failed. Please check your credentials.", + "wpslug" + ), + ]); + } + } catch (Exception $e) { + wp_send_json_error([ + "message" => + __("API connection failed: ", "wpslug") . $e->getMessage(), + ]); + } + } + + public function addPostMetaBox() + { + global $post; + + if (!$post || !current_user_can("edit_post", $post->ID)) { + return; + } + + $options = $this->settings->getOptions(); + + if ( + !$options["enable_conversion"] || + !$this->settings->isPostTypeEnabled($post->post_type) + ) { + return; + } + + echo '
'; + echo ""; + echo "
"; + } + + public function addBulkAction($bulk_actions) + { + $options = $this->settings->getOptions(); + if (!$options["enable_conversion"]) { + return $bulk_actions; + } + + $modes = $this->settings->getConversionModes(); + $action_text = sprintf( + __("Convert Slugs (%s)", "wpslug"), + $modes[$options["conversion_mode"]] + ); + $bulk_actions["wpslug-convert"] = $action_text; + return $bulk_actions; + } + + public function handleBulkAction($redirect_url, $action, $post_ids) + { + if ($action !== "wpslug-convert") { + return $redirect_url; + } + + $options = $this->settings->getOptions(); + $converted_count = 0; + + foreach ($post_ids as $post_id) { + $post = get_post($post_id); + if (!$post) { + continue; + } + + $new_slug = $this->converter->convert($post->post_title, $options); + $new_slug = $this->optimizer->optimize($new_slug, $options); + + if (!empty($new_slug) && $new_slug !== $post->post_name) { + $unique_slug = $this->optimizer->generateUniqueSlug( + $new_slug, + $post->ID, + $post->post_type + ); + wp_update_post([ + "ID" => $post->ID, + "post_name" => $unique_slug, + ]); + $converted_count++; + } + } + + $redirect_url = add_query_arg( + "wpslug-converted", + $converted_count, + $redirect_url + ); + return $redirect_url; + } + + public function bulkActionNotice() + { + if (isset($_GET["wpslug-converted"])) { + $count = intval($_GET["wpslug-converted"]); + echo '
'; + echo "

" . + sprintf( + __("Successfully converted %d slug(s).", "wpslug"), + $count + ) . + "

"; + echo "
"; + } + } +} diff --git a/includes/class-wpslug-converter.php b/includes/class-wpslug-converter.php new file mode 100644 index 0000000..81155e4 --- /dev/null +++ b/includes/class-wpslug-converter.php @@ -0,0 +1,293 @@ +pinyin = WPSlug_Pinyin::getInstance(); + $this->transliterator = new WPSlug_Transliterator(); + $this->translator = new WPSlug_Translator(); + $this->settings = new WPSlug_Settings(); + } + + public function convert($text, $options = array()) { + if (empty($text)) { + return ''; + } + + $mode = isset($options['conversion_mode']) ? $options['conversion_mode'] : 'pinyin'; + $start_time = microtime(true); + + try { + switch ($mode) { + case 'pinyin': + $result = $this->convertPinyin($text, $options); + break; + case 'transliteration': + $result = $this->convertTransliteration($text, $options); + break; + case 'translation': + $result = $this->convertTranslation($text, $options); + break; + default: + $result = $this->convertPinyin($text, $options); + } + + $execution_time = microtime(true) - $start_time; + $this->settings->updateConversionStats($mode, true, $execution_time); + + return $result; + + } catch (Exception $e) { + $execution_time = microtime(true) - $start_time; + $this->settings->updateConversionStats($mode, false, $execution_time); + $this->settings->logError('Conversion error in mode ' . $mode . ': ' . $e->getMessage(), array( + 'text' => $text, + 'mode' => $mode, + 'options' => $options + )); + + return $this->cleanBasicSlug($text, $options); + } + } + + private function convertPinyin($text, $options) { + try { + if ($this->detectLanguage($text) === 'zh') { + return $this->pinyin->convertToPinyin($text, $options); + } else { + return $this->cleanBasicSlug($text, $options); + } + } catch (Exception $e) { + $this->settings->logError('Pinyin conversion error: ' . $e->getMessage()); + return $this->cleanBasicSlug($text, $options); + } + } + + private function convertTransliteration($text, $options) { + try { + $detected_lang = $this->detectLanguage($text); + + if (in_array($detected_lang, array('ru', 'ar', 'el', 'he'))) { + return $this->transliterator->transliterate($text, $options); + } else { + return $this->cleanBasicSlug($text, $options); + } + } catch (Exception $e) { + $this->settings->logError('Transliteration error: ' . $e->getMessage()); + return $this->cleanBasicSlug($text, $options); + } + } + + private function convertTranslation($text, $options) { + try { + $service = isset($options['translation_service']) ? $options['translation_service'] : 'none'; + + if ($service === 'none') { + return $this->convertPinyin($text, $options); + } + + $detected_lang = $this->detectLanguage($text); + $target_lang = isset($options['translation_target_lang']) ? $options['translation_target_lang'] : 'en'; + + if ($detected_lang === $target_lang) { + return $this->cleanBasicSlug($text, $options); + } + + return $this->translator->translate($text, $options); + } catch (Exception $e) { + $this->settings->logError('Translation error: ' . $e->getMessage()); + return $this->convertPinyin($text, $options); + } + } + + private function cleanBasicSlug($text, $options) { + $text = strip_tags($text); + $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + $text = preg_replace('/&.+?;/', '', $text); + $text = preg_replace('/[^a-zA-Z0-9\s\-_\p{L}\p{N}]/u', '', $text); + $text = preg_replace('/\s+/', '-', $text); + $text = preg_replace('/\-+/', '-', $text); + $text = trim($text, '-_'); + + if (isset($options['force_lowercase']) && $options['force_lowercase']) { + $text = strtolower($text); + } + + return $text; + } + + public function detectLanguage($text) { + if (preg_match('/[\x{4e00}-\x{9fff}]/u', $text)) { + return 'zh'; + } + if (preg_match('/[\x{0400}-\x{04ff}]/u', $text)) { + return 'ru'; + } + if (preg_match('/[\x{0590}-\x{05ff}]/u', $text)) { + return 'he'; + } + if (preg_match('/[\x{0600}-\x{06ff}]/u', $text)) { + return 'ar'; + } + if (preg_match('/[\x{3040}-\x{309f}]/u', $text)) { + return 'ja'; + } + if (preg_match('/[\x{30a0}-\x{30ff}]/u', $text)) { + return 'ja'; + } + if (preg_match('/[\x{ac00}-\x{d7af}]/u', $text)) { + return 'ko'; + } + if (preg_match('/[\x{0370}-\x{03ff}]/u', $text)) { + return 'el'; + } + if (preg_match('/[\x{0100}-\x{017f}]/u', $text)) { + return 'latin-ext'; + } + if (preg_match('/[\x{0080}-\x{00ff}]/u', $text)) { + return 'latin-ext'; + } + if (preg_match('/[a-zA-Z]/', $text)) { + return 'en'; + } + + return 'unknown'; + } + + public function getSupportedModes() { + return array('pinyin', 'transliteration', 'translation'); + } + + public function isModeSupported($mode) { + return in_array($mode, $this->getSupportedModes()); + } + + public function batchConvert($items, $options = array()) { + $results = array(); + + if (!is_array($items)) { + return $results; + } + + foreach ($items as $item) { + try { + $converted = $this->convert($item, $options); + $results[] = array( + 'original' => $item, + 'converted' => $converted, + 'mode' => isset($options['conversion_mode']) ? $options['conversion_mode'] : 'pinyin', + 'detected_language' => $this->detectLanguage($item) + ); + } catch (Exception $e) { + $this->settings->logError('Batch convert error: ' . $e->getMessage()); + $results[] = array( + 'original' => $item, + 'converted' => sanitize_title($item), + 'mode' => 'fallback', + 'detected_language' => 'unknown' + ); + } + } + + return $results; + } + + public function testConversion($text, $options = array()) { + $start_time = microtime(true); + + try { + $detected_lang = $this->detectLanguage($text); + $converted = $this->convert($text, $options); + $execution_time = microtime(true) - $start_time; + + return array( + 'success' => true, + 'original' => $text, + 'converted' => $converted, + 'detected_language' => $detected_lang, + 'execution_time' => $execution_time, + 'mode' => isset($options['conversion_mode']) ? $options['conversion_mode'] : 'pinyin' + ); + + } catch (Exception $e) { + $execution_time = microtime(true) - $start_time; + + return array( + 'success' => false, + 'original' => $text, + 'converted' => sanitize_title($text), + 'detected_language' => 'unknown', + 'execution_time' => $execution_time, + 'mode' => 'fallback', + 'error' => $e->getMessage() + ); + } + } + + public function getLanguageInfo($text) { + $detected_lang = $this->detectLanguage($text); + $char_count = mb_strlen($text, 'UTF-8'); + $word_count = str_word_count($text, 0, 'àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ'); + + $info = array( + 'detected_language' => $detected_lang, + 'character_count' => $char_count, + 'word_count' => $word_count, + 'has_chinese' => preg_match('/[\x{4e00}-\x{9fff}]/u', $text) ? true : false, + 'has_cyrillic' => preg_match('/[\x{0400}-\x{04ff}]/u', $text) ? true : false, + 'has_arabic' => preg_match('/[\x{0600}-\x{06ff}]/u', $text) ? true : false, + 'has_greek' => preg_match('/[\x{0370}-\x{03ff}]/u', $text) ? true : false, + 'has_latin' => preg_match('/[a-zA-Z]/', $text) ? true : false, + 'has_numbers' => preg_match('/\d/', $text) ? true : false, + 'has_special_chars' => preg_match('/[^\w\s\p{L}\p{N}]/u', $text) ? true : false + ); + + return $info; + } + + public function recommendMode($text) { + $lang_info = $this->getLanguageInfo($text); + $detected_lang = $lang_info['detected_language']; + + if ($detected_lang === 'zh') { + return 'pinyin'; + } elseif (in_array($detected_lang, array('ru', 'ar', 'el', 'he'))) { + return 'transliteration'; + } elseif ($detected_lang !== 'en' && $detected_lang !== 'unknown') { + return 'translation'; + } else { + return 'pinyin'; + } + } + + public function validateInput($text, $options = array()) { + $max_length = isset($options['max_length']) ? intval($options['max_length']) : 1000; + + if (empty($text)) { + return array( + 'valid' => false, + 'error' => 'Input text is empty' + ); + } + + if ($max_length > 0 && mb_strlen($text, 'UTF-8') > $max_length) { + return array( + 'valid' => false, + 'error' => 'Input text exceeds maximum length of ' . $max_length . ' characters' + ); + } + + return array( + 'valid' => true, + 'message' => 'Input is valid' + ); + } +} \ No newline at end of file diff --git a/includes/class-wpslug-core.php b/includes/class-wpslug-core.php new file mode 100644 index 0000000..ab872e9 --- /dev/null +++ b/includes/class-wpslug-core.php @@ -0,0 +1,393 @@ +settings = new WPSlug_Settings(); + $this->converter = new WPSlug_Converter(); + $this->optimizer = new WPSlug_Optimizer(); + + if (is_admin()) { + $this->admin = new WPSlug_Admin(); + } + + $this->initHooks(); + } + + private function initHooks() { + add_filter('sanitize_title', array($this, 'processSanitizeTitle'), 9, 3); + add_filter('wp_insert_post_data', array($this, 'processPostData'), 10, 2); + add_filter('wp_insert_term_data', array($this, 'processTermData'), 10, 3); + add_filter('wp_update_term_data', array($this, 'processTermDataUpdate'), 10, 4); + add_filter('sanitize_file_name', array($this, 'processFileName'), 10, 2); + add_filter('wp_unique_post_slug', array($this, 'processUniquePostSlug'), 10, 6); + add_filter('pre_category_nicename', array($this, 'preCategoryNicename'), 10, 2); + + add_action('transition_post_status', array($this, 'handlePostStatusTransition'), 10, 3); + + if (is_admin()) { + add_filter('manage_posts_columns', array($this, 'addSlugColumn')); + add_action('manage_posts_custom_column', array($this, 'displaySlugColumn'), 10, 2); + add_filter('manage_pages_columns', array($this, 'addSlugColumn')); + add_action('manage_pages_custom_column', array($this, 'displaySlugColumn'), 10, 2); + } + } + + public function processSanitizeTitle($title, $raw_title = '', $context = 'display') { + if ($context !== 'save' || empty($title)) { + return $title; + } + + try { + $options = $this->settings->getOptions(); + + if (!$options['enable_conversion']) { + return $title; + } + + $processed_title = $this->converter->convert($title, $options); + $processed_title = $this->optimizer->optimize($processed_title, $options); + + return $processed_title; + } catch (Exception $e) { + $this->settings->logError('processSanitizeTitle error: ' . $e->getMessage()); + return $title; + } + } + + public function processPostData($data, $postarr) { + if (empty($data['post_title'])) { + return $data; + } + + try { + $options = $this->settings->getOptions(); + + if (!$options['enable_conversion'] || !$options['auto_convert']) { + return $data; + } + + $post_type = $data['post_type']; + if (!$this->settings->isPostTypeEnabled($post_type)) { + return $data; + } + + if (isset($postarr['wpslug_disable_conversion']) && $postarr['wpslug_disable_conversion']) { + return $data; + } + + if (!empty($data['post_name']) && !$this->shouldUpdateSlug($postarr)) { + return $data; + } + + $slug = $this->converter->convert($data['post_title'], $options); + $slug = $this->optimizer->optimize($slug, $options); + + if (!empty($slug) && $slug !== $data['post_name']) { + $data['post_name'] = $slug; + } + + return $data; + } catch (Exception $e) { + $this->settings->logError('processPostData error: ' . $e->getMessage()); + return $data; + } + } + + public function processTermData($data, $taxonomy, $args) { + try { + $options = $this->settings->getOptions(); + + if (!$options['enable_conversion'] || !$options['auto_convert']) { + return $data; + } + + if (!$this->settings->isTaxonomyEnabled($taxonomy)) { + return $data; + } + + if (!empty($data['name']) && empty($args['slug'])) { + $slug = $this->converter->convert($data['name'], $options); + $slug = $this->optimizer->optimize($slug, $options); + + if (!empty($slug)) { + $data['slug'] = $slug; + } + } + + return $data; + } catch (Exception $e) { + $this->settings->logError('processTermData error: ' . $e->getMessage()); + return $data; + } + } + + public function processTermDataUpdate($data, $term_id, $taxonomy, $args) { + try { + $options = $this->settings->getOptions(); + + if (!$options['enable_conversion'] || !$options['auto_convert']) { + return $data; + } + + if (!$this->settings->isTaxonomyEnabled($taxonomy)) { + return $data; + } + + if (!empty($data['name']) && empty($args['slug'])) { + $slug = $this->converter->convert($data['name'], $options); + $slug = $this->optimizer->optimize($slug, $options); + + if (!empty($slug)) { + $data['slug'] = wp_unique_term_slug($slug, (object) $args); + } + } + + return $data; + } catch (Exception $e) { + $this->settings->logError('processTermDataUpdate error: ' . $e->getMessage()); + return $data; + } + } + + public function processFileName($filename, $filename_raw = '') { + try { + $options = $this->settings->getOptions(); + + if (!$options['enable_conversion'] || $options['disable_file_convert']) { + return $filename; + } + + $media_mode = $this->settings->getOption('media_conversion_mode', 'normal'); + $media_prefix = $this->settings->getOption('media_file_prefix', ''); + + $parts = explode('.', $filename); + $extension = ''; + + if (count($parts) > 1) { + $extension = array_pop($parts); + $name = implode('.', $parts); + } else { + $name = $filename; + } + + switch ($media_mode) { + case 'md5': + $converted_name = md5($name . time()); + break; + + case 'none': + $converted_name = $name; + break; + + case 'normal': + default: + if ($this->needsConversion($name)) { + $converted_name = $this->converter->convert($name, $options); + $converted_name = $this->optimizer->optimize($converted_name, $options); + } else { + $converted_name = $name; + } + break; + } + + if (!empty($media_prefix)) { + $converted_name = $media_prefix . $converted_name; + } + + return $extension ? $converted_name . '.' . $extension : $converted_name; + } catch (Exception $e) { + $this->settings->logError('processFileName error: ' . $e->getMessage()); + return $filename; + } + } + + public function processUniquePostSlug($slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug) { + try { + $options = $this->settings->getOptions(); + + if (!$options['enable_conversion'] || !$options['auto_convert']) { + return $slug; + } + + if ($post_type === 'attachment') { + return $slug; + } + + if (!$this->settings->isPostTypeEnabled($post_type)) { + return $slug; + } + + $old_status = get_post_field('post_status', $post_ID, 'edit'); + + if ($old_status !== 'publish' && $post_status === 'publish') { + $converted_slug = $this->converter->convert($slug, $options); + $converted_slug = $this->optimizer->optimize($converted_slug, $options); + if (!empty($converted_slug)) { + return $converted_slug; + } + } + + return $slug; + } catch (Exception $e) { + $this->settings->logError('processUniquePostSlug error: ' . $e->getMessage()); + return $slug; + } + } + + public function preCategoryNicename($slug, $name = '') { + try { + $options = $this->settings->getOptions(); + + if (!$options['enable_conversion'] || !$options['auto_convert']) { + return $slug; + } + + if ($slug) { + return $slug; + } + + $tag_name = isset($_POST['tag-name']) ? sanitize_text_field($_POST['tag-name']) : $name; + + if ($tag_name) { + $converted_slug = $this->converter->convert($tag_name, $options); + $converted_slug = $this->optimizer->optimize($converted_slug, $options); + return sanitize_title($converted_slug); + } + + return $slug; + } catch (Exception $e) { + $this->settings->logError('preCategoryNicename error: ' . $e->getMessage()); + return $slug; + } + } + + public function handlePostStatusTransition($new_status, $old_status, $post) { + if ($new_status !== 'publish' || $old_status === 'publish') { + return; + } + + try { + $options = $this->settings->getOptions(); + + if (!$options['enable_conversion'] || !$options['auto_convert']) { + return; + } + + if (!$this->settings->isPostTypeEnabled($post->post_type)) { + return; + } + + $new_slug = $this->converter->convert($post->post_title, $options); + $new_slug = $this->optimizer->optimize($new_slug, $options); + + if (!empty($new_slug) && $new_slug !== $post->post_name) { + $unique_slug = $this->optimizer->generateUniqueSlug($new_slug, $post->ID, $post->post_type); + + wp_update_post(array( + 'ID' => $post->ID, + 'post_name' => $unique_slug + )); + } + } catch (Exception $e) { + $this->settings->logError('handlePostStatusTransition error: ' . $e->getMessage()); + } + } + + public function addSlugColumn($columns) { + try { + $options = $this->settings->getOptions(); + + if (isset($options['show_slug_column']) && $options['show_slug_column']) { + $columns['wpslug_slug'] = __('Slug', 'wpslug'); + } + + return $columns; + } catch (Exception $e) { + return $columns; + } + } + + public function displaySlugColumn($column_name, $post_id) { + if ($column_name !== 'wpslug_slug') { + return; + } + + try { + $post = get_post($post_id); + if (!$post || $post->post_status === 'trash') { + echo '' . esc_html__('N/A', 'wpslug') . ''; + return; + } + + $permalink = get_permalink($post_id); + $home_url = trailingslashit(home_url()); + + if ($permalink && strpos($permalink, $home_url) === 0) { + $slug = str_replace($home_url, '/', $permalink); + } else { + $slug = '/' . $post->post_name; + } + + echo '' . esc_html($slug) . ''; + } catch (Exception $e) { + echo '' . esc_html__('Error', 'wpslug') . ''; + } + } + + private function needsConversion($text) { + return preg_match('/[^\x00-\x7F]/', $text); + } + + private function shouldUpdateSlug($postarr) { + if (isset($postarr['post_status']) && $postarr['post_status'] === 'auto-draft') { + return true; + } + + if (isset($postarr['ID']) && $postarr['ID'] > 0) { + $existing_post = get_post($postarr['ID']); + if ($existing_post && $existing_post->post_status === 'auto-draft') { + return true; + } + } + + return false; + } + + public function activate() { + try { + $this->settings->createDefaultOptions(); + flush_rewrite_rules(); + } catch (Exception $e) { + $this->settings->logError('activate error: ' . $e->getMessage()); + } + } + + public function deactivate() { + flush_rewrite_rules(); + } + + public function getSettings() { + return $this->settings; + } + + public function getConverter() { + return $this->converter; + } + + public function getOptimizer() { + return $this->optimizer; + } + + public function getAdmin() { + return $this->admin; + } +} \ No newline at end of file diff --git a/includes/class-wpslug-optimizer.php b/includes/class-wpslug-optimizer.php new file mode 100644 index 0000000..0b28a3e --- /dev/null +++ b/includes/class-wpslug-optimizer.php @@ -0,0 +1,302 @@ +applySEOOptimizations($text, $options); + } + + if ($max_length > 0 && strlen($text) > $max_length) { + $text = $this->truncateSlug($text, $max_length); + } + + $text = $this->finalCleanup($text); + + if ($force_lowercase) { + $text = strtolower($text); + } + + return $text; + } + + private function applySEOOptimizations($text, $options) { + if (isset($options['smart_punctuation']) && $options['smart_punctuation']) { + $text = $this->handleSmartPunctuation($text); + } + + if (isset($options['mixed_content_optimization']) && $options['mixed_content_optimization']) { + $text = $this->optimizeMixedContent($text); + } + + if (isset($options['remove_stop_words']) && $options['remove_stop_words']) { + $text = $this->removeStopWords($text, $options); + } + + if (isset($options['seo_max_words']) && $options['seo_max_words'] > 0) { + $text = $this->limitWords($text, $options['seo_max_words']); + } + + return $text; + } + + private function handleSmartPunctuation($text) { + $text = str_replace(array(':', ';', ','), '-', $text); + $text = str_replace(array('.', '?', '!', '(', ')', '[', ']', '<', '>'), '', $text); + $text = str_replace(array('|', '/', '\\'), '-', $text); + $text = str_replace('&', 'and', $text); + $text = str_replace('+', 'plus', $text); + $text = str_replace('=', 'equal', $text); + $text = str_replace('%', 'percent', $text); + $text = str_replace('#', 'hash', $text); + $text = str_replace('@', 'at', $text); + $text = str_replace('$', 'dollar', $text); + + return $text; + } + + private function optimizeMixedContent($text) { + $text = preg_replace('/(\d+)(\p{Han})/u', '$1-$2', $text); + $text = preg_replace('/(\p{Han})(\d+)/u', '$1-$2', $text); + + $text = preg_replace('/([a-zA-Z])(\p{Han})/u', '$1-$2', $text); + $text = preg_replace('/(\p{Han})([a-zA-Z])/u', '$1-$2', $text); + + $text = preg_replace('/([a-zA-Z])(\d+)/u', '$1$2', $text); + $text = preg_replace('/(\d+)([a-zA-Z])/u', '$1$2', $text); + + $text = preg_replace('/\s*-\s*/', '-', $text); + + return $text; + } + + private function removeStopWords($text, $options) { + if (!isset($options['stop_words_list'])) { + return $text; + } + + $stop_words_string = $options['stop_words_list']; + if (empty($stop_words_string)) { + return $text; + } + + $stop_words = explode(',', $stop_words_string); + $stop_words = array_map('trim', $stop_words); + $stop_words = array_filter($stop_words); + + if (empty($stop_words)) { + return $text; + } + + $words = preg_split('/[-\s_]+/', $text); + $filtered_words = array(); + + foreach ($words as $word) { + $word = trim($word); + if (empty($word)) { + continue; + } + + if (!in_array(strtolower($word), array_map('strtolower', $stop_words))) { + $filtered_words[] = $word; + } + } + + return implode('-', $filtered_words); + } + + private function limitWords($text, $max_words) { + if ($max_words <= 0) { + return $text; + } + + $words = preg_split('/[-\s_]+/', $text); + $words = array_filter($words, function($word) { + return !empty(trim($word)); + }); + + if (count($words) <= $max_words) { + return $text; + } + + $limited_words = array_slice($words, 0, $max_words); + return implode('-', $limited_words); + } + + private function finalCleanup($slug) { + $slug = preg_replace('/[^a-zA-Z0-9\-_\p{Han}]/u', '', $slug); + $slug = preg_replace('/\-+/', '-', $slug); + $slug = preg_replace('/_+/', '_', $slug); + $slug = trim($slug, '-_'); + + return $slug; + } + + public function truncateSlug($slug, $max_length) { + if (strlen($slug) <= $max_length) { + return $slug; + } + + $parts = explode('-', $slug); + $result = ''; + + foreach ($parts as $part) { + if (strlen($result . '-' . $part) <= $max_length) { + $result .= ($result ? '-' : '') . $part; + } else { + break; + } + } + + return $result ?: substr($slug, 0, $max_length); + } + + public function generateUniqueSlug($slug, $post_id = 0, $post_type = 'post') { + global $wpdb; + + $original_slug = $slug; + $suffix = 1; + + while (true) { + $query = $wpdb->prepare(" + SELECT ID FROM {$wpdb->posts} + WHERE post_name = %s + AND post_type = %s + AND ID != %d + LIMIT 1 + ", $slug, $post_type, $post_id); + + if (!$wpdb->get_var($query)) { + break; + } + + $slug = $original_slug . '-' . $suffix; + $suffix++; + + if ($suffix > 100) { + break; + } + } + + return $slug; + } + + public function validateSlug($slug) { + if (empty($slug)) { + return false; + } + + if (strlen($slug) > 200) { + return false; + } + + if (preg_match('/[^a-zA-Z0-9\-_\p{Han}]/u', $slug)) { + return false; + } + + return true; + } + + public function detectLanguage($text) { + if (preg_match('/[\x{4e00}-\x{9fff}]/u', $text)) { + return 'zh'; + } + + return 'en'; + } + + public function getSEOScore($original_text, $optimized_slug) { + $score = 0; + $max_score = 100; + + if (strlen($optimized_slug) > 0) { + $score += 20; + } + + if (strlen($optimized_slug) <= 60) { + $score += 15; + } + + if (preg_match('/^[a-zA-Z0-9\-_\p{Han}]+$/u', $optimized_slug)) { + $score += 15; + } + + if (substr_count($optimized_slug, '-') <= 5) { + $score += 10; + } + + if (!preg_match('/^-|-$/', $optimized_slug)) { + $score += 10; + } + + $word_count = count(explode('-', $optimized_slug)); + if ($word_count >= 2 && $word_count <= 5) { + $score += 15; + } + + if (strtolower($optimized_slug) === $optimized_slug) { + $score += 5; + } + + if (!preg_match('/\d{4,}/', $optimized_slug)) { + $score += 5; + } + + if (strlen($optimized_slug) >= 10) { + $score += 5; + } + + return min($score, $max_score); + } + + public function suggestAlternatives($text, $options = array()) { + $suggestions = array(); + + $base_slug = $this->optimize($text, $options); + $suggestions[] = $base_slug; + + $short_options = $options; + $short_options['seo_max_words'] = 3; + $short_slug = $this->optimize($text, $short_options); + if ($short_slug !== $base_slug) { + $suggestions[] = $short_slug; + } + + $no_stop_words_options = $options; + $no_stop_words_options['remove_stop_words'] = true; + $no_stop_words_slug = $this->optimize($text, $no_stop_words_options); + if ($no_stop_words_slug !== $base_slug) { + $suggestions[] = $no_stop_words_slug; + } + + $minimal_options = $options; + $minimal_options['seo_max_words'] = 2; + $minimal_options['remove_stop_words'] = true; + $minimal_slug = $this->optimize($text, $minimal_options); + if ($minimal_slug !== $base_slug && !in_array($minimal_slug, $suggestions)) { + $suggestions[] = $minimal_slug; + } + + return array_unique($suggestions); + } +} \ No newline at end of file diff --git a/includes/class-wpslug-pinyin.php b/includes/class-wpslug-pinyin.php new file mode 100644 index 0000000..4bdc490 --- /dev/null +++ b/includes/class-wpslug-pinyin.php @@ -0,0 +1,166 @@ +initPinyinDict(); + } + + public function convertToPinyin($text, $options = array()) { + if (empty($text)) { + return ''; + } + + $separator = isset($options['pinyin_separator']) ? $options['pinyin_separator'] : '-'; + $format = isset($options['pinyin_format']) ? $options['pinyin_format'] : 'full'; + $max_length = isset($options['max_length']) ? (int)$options['max_length'] : 100; + $preserve_english = isset($options['preserve_english']) ? $options['preserve_english'] : true; + $preserve_numbers = isset($options['preserve_numbers']) ? $options['preserve_numbers'] : true; + + if ($max_length > 0 && mb_strlen($text, 'UTF-8') > $max_length) { + $text = mb_substr($text, 0, $max_length, 'UTF-8'); + } + + $result = ''; + $text_array = $this->mbStrSplit($text); + + foreach ($text_array as $char) { + if ($this->isChinese($char)) { + $pinyin = $this->getPinyinForChar($char); + if (!empty($pinyin)) { + if ($format === 'first') { + $first_letter = mb_substr($pinyin, 0, 1, 'UTF-8'); + $result .= $separator . strtolower($first_letter) . $separator; + } else { + $result .= $separator . strtolower($pinyin) . $separator; + } + } + } else { + if ($preserve_english && preg_match('/[a-zA-Z]/', $char)) { + $result .= $char; + } elseif ($preserve_numbers && preg_match('/[0-9]/', $char)) { + $result .= $char; + } elseif (preg_match('/\s/', $char)) { + $result .= $separator; + } + } + } + + if (!empty($separator)) { + $result = trim(preg_replace('/' . preg_quote($separator, '/') . '+/', $separator, $result), $separator); + } + + return $result; + } + + public function isChinese($char) { + return preg_match('/[\x{4e00}-\x{9fff}]/u', $char); + } + + public function detectLanguage($text) { + if (preg_match('/[\x{4e00}-\x{9fff}]/u', $text)) { + return 'zh'; + } + return 'en'; + } + + private function getPinyinForChar($char) { + if (isset($this->pinyin_dict[$char])) { + return $this->pinyin_dict[$char]; + } + return ''; + } + + private function mbStrSplit($string, $length = 1) { + if (function_exists('mb_str_split')) { + return mb_str_split($string, $length, 'UTF-8'); + } + + $result = array(); + $string_length = mb_strlen($string, 'UTF-8'); + + for ($i = 0; $i < $string_length; $i += $length) { + $result[] = mb_substr($string, $i, $length, 'UTF-8'); + } + + return $result; + } + + private function initPinyinDict() { + $dictionary_file = WPSLUG_PLUGIN_DIR . 'includes/dictionary.php'; + + if (file_exists($dictionary_file)) { + $dictionary = include $dictionary_file; + + if (is_array($dictionary)) { + foreach ($dictionary as $pinyin => $chars) { + $pinyin_lower = strtolower($pinyin); + $char_array = $this->mbStrSplit($chars); + + foreach ($char_array as $char) { + if (!empty($char)) { + $this->pinyin_dict[$char] = $pinyin_lower; + } + } + } + } + } else { + $this->initFallbackDict(); + } + } + + private function initFallbackDict() { + $this->pinyin_dict = array( + '一' => 'yi', '二' => 'er', '三' => 'san', '四' => 'si', '五' => 'wu', + '六' => 'liu', '七' => 'qi', '八' => 'ba', '九' => 'jiu', '十' => 'shi', + '的' => 'de', '了' => 'le', '是' => 'shi', '我' => 'wo', '你' => 'ni', + '他' => 'ta', '她' => 'ta', '它' => 'ta', '好' => 'hao', '很' => 'hen', + '都' => 'dou', '会' => 'hui', '个' => 'ge', '这' => 'zhe', '那' => 'na', + '中' => 'zhong', '国' => 'guo', '人' => 'ren', '有' => 'you', '来' => 'lai', + '可' => 'ke', '以' => 'yi', '上' => 'shang', '下' => 'xia', '大' => 'da', + '小' => 'xiao', '多' => 'duo', '少' => 'shao', '什' => 'shen', '么' => 'me', + '时' => 'shi', '间' => 'jian', '地' => 'di', '方' => 'fang', '年' => 'nian', + '月' => 'yue', '日' => 'ri', '天' => 'tian', '水' => 'shui', '火' => 'huo', + '木' => 'mu', '金' => 'jin', '土' => 'tu', '山' => 'shan', '海' => 'hai', + '河' => 'he', '学' => 'xue', '校' => 'xiao', '老' => 'lao', '师' => 'shi', + '生' => 'sheng', '活' => 'huo', '工' => 'gong', '作' => 'zuo', '家' => 'jia', + '庭' => 'ting', '朋' => 'peng', '友' => 'you', '爱' => 'ai', '情' => 'qing', + '心' => 'xin', '想' => 'xiang', '知' => 'zhi', '道' => 'dao', '看' => 'kan', + '见' => 'jian', '听' => 'ting', '说' => 'shuo', '话' => 'hua', '言' => 'yan', + '文' => 'wen', '字' => 'zi', '书' => 'shu', '读' => 'du', '写' => 'xie', + '画' => 'hua', '吃' => 'chi', '喝' => 'he', '睡' => 'shui', '觉' => 'jue', + '走' => 'zou', '跑' => 'pao', '飞' => 'fei', '坐' => 'zuo', '站' => 'zhan', + '躺' => 'tang', '笑' => 'xiao', '哭' => 'ku', '高' => 'gao', '兴' => 'xing', + '快' => 'kuai', '乐' => 'le', '难' => 'nan', '过' => 'guo', '新' => 'xin', + '旧' => 'jiu', '长' => 'chang', '短' => 'duan', '宽' => 'kuan', '窄' => 'zhai', + '厚' => 'hou', '薄' => 'bao', '深' => 'shen', '浅' => 'qian', '远' => 'yuan', + '近' => 'jin', '美' => 'mei', '丽' => 'li', '漂' => 'piao', '亮' => 'liang', + '帅' => 'shuai', '聪' => 'cong', '明' => 'ming', '笨' => 'ben', '懒' => 'lan', + '勤' => 'qin', '忙' => 'mang', '闲' => 'xian', '累' => 'lei', '轻' => 'qing', + '重' => 'zhong', '松' => 'song', '紧' => 'jin', '开' => 'kai', '关' => 'guan', + '门' => 'men', '窗' => 'chuang', '户' => 'hu', '房' => 'fang', '子' => 'zi', + '屋' => 'wu', '楼' => 'lou', '层' => 'ceng', '街' => 'jie', '路' => 'lu', + '桥' => 'qiao', '车' => 'che', '船' => 'chuan', '机' => 'ji', '电' => 'dian', + '话' => 'hua', '视' => 'shi', '脑' => 'nao', '手' => 'shou', '网' => 'wang', + '络' => 'luo', '游' => 'you', '戏' => 'xi', '音' => 'yin', '影' => 'ying', + '唱' => 'chang', '歌' => 'ge', '跳' => 'tiao', '舞' => 'wu', '购' => 'gou', + '物' => 'wu', '买' => 'mai', '卖' => 'mai', '钱' => 'qian', '价' => 'jia', + '格' => 'ge', '便' => 'bian', '宜' => 'yi', '贵' => 'gui', '医' => 'yi', + '院' => 'yuan', '病' => 'bing', '痛' => 'tong', '健' => 'jian', '康' => 'kang', + '运' => 'yun', '动' => 'dong', '锻' => 'duan', '炼' => 'lian' + ); + } +} \ No newline at end of file diff --git a/includes/class-wpslug-settings.php b/includes/class-wpslug-settings.php new file mode 100644 index 0000000..7a472ff --- /dev/null +++ b/includes/class-wpslug-settings.php @@ -0,0 +1,705 @@ +initDefaults(); + } + + private function initDefaults() + { + $this->defaults = [ + "enable_conversion" => true, + "conversion_mode" => "pinyin", + "pinyin_separator" => "-", + "pinyin_format" => "full", + "max_length" => 50, + "force_lowercase" => true, + "transliteration_method" => "basic", + "translation_service" => "none", + "google_api_key" => "", + "baidu_app_id" => "", + "baidu_secret_key" => "", + "translation_source_lang" => "auto", + "translation_target_lang" => "en", + "enabled_post_types" => ["post", "page"], + "enabled_taxonomies" => ["category", "post_tag"], + "auto_convert" => true, + "preserve_english" => true, + "preserve_numbers" => true, + "disable_file_convert" => false, + "media_conversion_mode" => "normal", + "media_file_prefix" => "", + "preserve_media_extension" => true, + "show_slug_column" => false, + "enable_seo_optimization" => true, + "remove_stop_words" => true, + "smart_punctuation" => true, + "mixed_content_optimization" => true, + "seo_max_words" => 20, + "stop_words_list" => + "the,a,an,and,or,but,in,on,at,to,for,of,with,by,from,up,about,into,through,during,before,after,above,below,between,among,since,without,within", + ]; + } + + public function getOptions() + { + $options = get_option($this->option_name, []); + return wp_parse_args($options, $this->defaults); + } + + public function getOption($key, $default = null) + { + $options = $this->getOptions(); + + if (isset($options[$key])) { + return $options[$key]; + } + + return $default !== null + ? $default + : (isset($this->defaults[$key]) + ? $this->defaults[$key] + : null); + } + + public function updateOption($key, $value) + { + $options = $this->getOptions(); + $options[$key] = $value; + return update_option($this->option_name, $options); + } + + public function updateOptions($new_options) + { + $current_options = $this->getOptions(); + $merged_options = array_merge($current_options, $new_options); + return update_option($this->option_name, $merged_options); + } + + public function resetOptions() + { + return update_option($this->option_name, $this->defaults); + } + + public function createDefaultOptions() + { + if (false === get_option($this->option_name)) { + add_option($this->option_name, $this->defaults); + } + } + + public function validateOptions($options) + { + if (!is_array($options)) { + return $this->defaults; + } + + $validated = []; + + foreach ($this->defaults as $key => $default_value) { + $value = isset($options[$key]) ? $options[$key] : $default_value; + + switch ($key) { + case "enable_conversion": + case "force_lowercase": + case "auto_convert": + case "preserve_english": + case "preserve_numbers": + case "disable_file_convert": + case "preserve_media_extension": + case "show_slug_column": + case "enable_seo_optimization": + case "remove_stop_words": + case "smart_punctuation": + case "mixed_content_optimization": + $validated[$key] = WPSlug_Validator::validateBoolean( + $value + ); + break; + + case "conversion_mode": + $validated[$key] = WPSlug_Validator::validateConversionMode( + $value + ); + break; + + case "pinyin_separator": + $valid_separators = ["-", "_", ""]; + $validated[$key] = WPSlug_Validator::validateSelect( + $value, + $valid_separators, + "-" + ); + break; + + case "pinyin_format": + $valid_formats = ["full", "first"]; + $validated[$key] = WPSlug_Validator::validateSelect( + $value, + $valid_formats, + "full" + ); + break; + + case "transliteration_method": + $validated[ + $key + ] = WPSlug_Validator::validateTransliterationMethod($value); + break; + + case "translation_service": + $validated[ + $key + ] = WPSlug_Validator::validateTranslationService($value); + break; + + case "media_conversion_mode": + $valid_modes = ["normal", "md5", "none"]; + $validated[$key] = WPSlug_Validator::validateSelect( + $value, + $valid_modes, + "normal" + ); + break; + + case "translation_source_lang": + case "translation_target_lang": + $default_lang = + $key === "translation_source_lang" ? "auto" : "en"; + $validated[$key] = + WPSlug_Validator::validateLanguageCode($value) ?: + $default_lang; + break; + + case "max_length": + $validated[$key] = WPSlug_Validator::validateInteger( + $value, + 0, + 500 + ); + break; + + case "seo_max_words": + $validated[$key] = WPSlug_Validator::validateInteger( + $value, + 1, + 30 + ); + break; + + case "enabled_post_types": + $validated[$key] = WPSlug_Validator::validatePostTypes( + $value + ); + break; + + case "enabled_taxonomies": + $validated[$key] = WPSlug_Validator::validateTaxonomies( + $value + ); + break; + + case "stop_words_list": + $validated[$key] = WPSlug_Validator::validateTextarea( + $value + ); + break; + + case "media_file_prefix": + $validated[$key] = WPSlug_Validator::validateString( + $value, + 50 + ); + break; + + case "google_api_key": + case "baidu_app_id": + case "baidu_secret_key": + $validated[$key] = WPSlug_Validator::validateApiKey($value); + break; + + default: + $validated[$key] = WPSlug_Validator::validateString($value); + } + } + + return $validated; + } + + public function getConversionModes() + { + return [ + "pinyin" => __("Chinese Pinyin Conversion", "wpslug"), + "transliteration" => __( + "Foreign Language Transliteration", + "wpslug" + ), + "translation" => __("Multi-language Translation", "wpslug"), + ]; + } + + public function getTransliterationMethods() + { + $methods = [ + "basic" => __("Basic Character Mapping", "wpslug"), + ]; + + if (function_exists("iconv")) { + $methods["iconv"] = __("iconv Transliteration", "wpslug"); + } + + if (class_exists("Transliterator")) { + $methods["intl"] = __("PHP Intl Extension", "wpslug"); + } + + return $methods; + } + + public function getTranslationServices() + { + return [ + "none" => __("None", "wpslug"), + "google" => __("Google Translate", "wpslug"), + "baidu" => __("Baidu Translate", "wpslug"), + ]; + } + + public function getLanguages() + { + return [ + "auto" => __("Auto Detect", "wpslug"), + "zh" => __("Chinese (Simplified)", "wpslug"), + "zh-TW" => __("Chinese (Traditional)", "wpslug"), + "en" => __("English", "wpslug"), + "es" => __("Spanish", "wpslug"), + "fr" => __("French", "wpslug"), + "de" => __("German", "wpslug"), + "ja" => __("Japanese", "wpslug"), + "ko" => __("Korean", "wpslug"), + "ru" => __("Russian", "wpslug"), + "ar" => __("Arabic", "wpslug"), + "it" => __("Italian", "wpslug"), + "pt" => __("Portuguese", "wpslug"), + "nl" => __("Dutch", "wpslug"), + "pl" => __("Polish", "wpslug"), + "tr" => __("Turkish", "wpslug"), + "sv" => __("Swedish", "wpslug"), + "da" => __("Danish", "wpslug"), + "no" => __("Norwegian", "wpslug"), + "fi" => __("Finnish", "wpslug"), + "cs" => __("Czech", "wpslug"), + "hu" => __("Hungarian", "wpslug"), + "ro" => __("Romanian", "wpslug"), + "bg" => __("Bulgarian", "wpslug"), + "hr" => __("Croatian", "wpslug"), + "sk" => __("Slovak", "wpslug"), + "sl" => __("Slovenian", "wpslug"), + "et" => __("Estonian", "wpslug"), + "lv" => __("Latvian", "wpslug"), + "lt" => __("Lithuanian", "wpslug"), + "mt" => __("Maltese", "wpslug"), + "el" => __("Greek", "wpslug"), + "cy" => __("Welsh", "wpslug"), + ]; + } + + public function getPostTypes() + { + $post_types = get_post_types(["public" => true], "objects"); + $enabled_post_types = $this->getOption("enabled_post_types", []); + + if (empty($enabled_post_types)) { + return $post_types; + } + + $filtered_post_types = []; + foreach ($post_types as $post_type) { + if (in_array($post_type->name, $enabled_post_types)) { + $filtered_post_types[$post_type->name] = $post_type; + } + } + + return $filtered_post_types; + } + + public function getTaxonomies() + { + $taxonomies = get_taxonomies(["public" => true], "objects"); + $enabled_taxonomies = $this->getOption("enabled_taxonomies", []); + + if (empty($enabled_taxonomies)) { + return $taxonomies; + } + + $filtered_taxonomies = []; + foreach ($taxonomies as $taxonomy) { + if (in_array($taxonomy->name, $enabled_taxonomies)) { + $filtered_taxonomies[$taxonomy->name] = $taxonomy; + } + } + + return $filtered_taxonomies; + } + + public function isPostTypeEnabled($post_type) + { + $enabled_post_types = $this->getOption("enabled_post_types", []); + return empty($enabled_post_types) || + in_array($post_type, $enabled_post_types); + } + + public function isTaxonomyEnabled($taxonomy) + { + $enabled_taxonomies = $this->getOption("enabled_taxonomies", []); + return empty($enabled_taxonomies) || + in_array($taxonomy, $enabled_taxonomies); + } + + public function exportOptions() + { + $options = $this->getOptions(); + $export_data = [ + "version" => WPSLUG_VERSION, + "timestamp" => time(), + "site_url" => home_url(), + "options" => $options, + ]; + + return json_encode($export_data, JSON_PRETTY_PRINT); + } + + public function importOptions($json_data) + { + $data = json_decode($json_data, true); + + if (!is_array($data) || !isset($data["options"])) { + return new WP_Error( + "invalid_data", + __("Invalid import data format.", "wpslug") + ); + } + + $options = $data["options"]; + $validated_options = $this->validateOptions($options); + + if (update_option($this->option_name, $validated_options)) { + return true; + } + + return new WP_Error( + "update_failed", + __("Failed to update options.", "wpslug") + ); + } + + public function uninstall() + { + delete_option($this->option_name); + delete_option("wpslug_conversion_stats"); + delete_option("wpslug_error_log"); + delete_option("wpslug_cache"); + + global $wpdb; + $wpdb->query( + "DELETE FROM {$wpdb->options} WHERE option_name LIKE 'wpslug_%'" + ); + } + + public function getDefaults() + { + return $this->defaults; + } + + public function getOptionName() + { + return $this->option_name; + } + + public function updateConversionStats( + $mode, + $success = true, + $execution_time = 0 + ) { + $stats = get_option("wpslug_conversion_stats", [ + "total_conversions" => 0, + "successful_conversions" => 0, + "failed_conversions" => 0, + "last_conversion" => null, + "most_used_mode" => "pinyin", + "performance_data" => [], + ]); + + $stats["total_conversions"]++; + if ($success) { + $stats["successful_conversions"]++; + } else { + $stats["failed_conversions"]++; + } + + $stats["last_conversion"] = current_time("mysql"); + $stats["most_used_mode"] = $mode; + + if ($execution_time > 0) { + $stats["performance_data"][] = [ + "mode" => $mode, + "time" => $execution_time, + "timestamp" => time(), + ]; + + $stats["performance_data"] = array_slice( + $stats["performance_data"], + -100 + ); + } + + update_option("wpslug_conversion_stats", $stats); + } + + public function logError($message, $context = []) + { + $log_entry = [ + "timestamp" => current_time("mysql"), + "message" => $message, + "context" => $context, + "backtrace" => wp_debug_backtrace_summary(), + ]; + + $error_log = get_option("wpslug_error_log", []); + $error_log[] = $log_entry; + + if (count($error_log) > 100) { + $error_log = array_slice($error_log, -100); + } + + update_option("wpslug_error_log", $error_log); + + if (defined("WP_DEBUG") && WP_DEBUG) { + error_log( + "WP Slug Plugin: " . + $message . + " | Context: " . + json_encode($context) + ); + } + } + + public function isFeatureEnabled($feature) + { + $features = [ + "auto_convert" => $this->getOption("auto_convert"), + "file_convert" => !$this->getOption("disable_file_convert"), + "slug_column" => $this->getOption("show_slug_column"), + "seo_optimization" => $this->getOption("enable_seo_optimization"), + "stop_words" => $this->getOption("remove_stop_words"), + "smart_punctuation" => $this->getOption("smart_punctuation"), + "mixed_content" => $this->getOption("mixed_content_optimization"), + ]; + + return isset($features[$feature]) ? $features[$feature] : false; + } + + public function getStopWords() + { + $stop_words_string = $this->getOption("stop_words_list", ""); + if (empty($stop_words_string)) { + return []; + } + + $stop_words = explode(",", $stop_words_string); + return array_map("trim", $stop_words); + } + + public function isModeEnabled($mode) + { + $conversion_mode = $this->getOption("conversion_mode"); + return $conversion_mode === $mode; + } + + public function isFirstLetterMode() + { + $conversion_mode = $this->getOption("conversion_mode"); + $pinyin_format = $this->getOption("pinyin_format"); + return $conversion_mode === "pinyin" && $pinyin_format === "first"; + } + + public function shouldApplySEO() + { + $seo_enabled = $this->getOption("enable_seo_optimization"); + $is_first_letter = $this->isFirstLetterMode(); + return $seo_enabled && !$is_first_letter; + } + + public function getMediaConversionModes() + { + return [ + "normal" => __("Normal Conversion (same as content)", "wpslug"), + "md5" => __("MD5 Hash (generates unique hash)", "wpslug"), + "none" => __("No Conversion (keep original)", "wpslug"), + ]; + } + + public function isMediaConversionEnabled() + { + return !$this->getOption("disable_file_convert"); + } + + public function getMediaConversionMode() + { + return $this->getOption("media_conversion_mode", "normal"); + } + + public function getMediaFilePrefix() + { + return $this->getOption("media_file_prefix", ""); + } + + public function shouldPreserveMediaExtension() + { + return $this->getOption("preserve_media_extension", true); + } + + public function getConversionStats() + { + return get_option("wpslug_conversion_stats", [ + "total_conversions" => 0, + "successful_conversions" => 0, + "failed_conversions" => 0, + "last_conversion" => null, + "most_used_mode" => "pinyin", + "performance_data" => [], + ]); + } + + public function getErrorLog() + { + return get_option("wpslug_error_log", []); + } + + public function clearErrorLog() + { + return delete_option("wpslug_error_log"); + } + + public function clearConversionStats() + { + return delete_option("wpslug_conversion_stats"); + } + + public function getSystemInfo() + { + $info = [ + "plugin_version" => WPSLUG_VERSION, + "wordpress_version" => get_bloginfo("version"), + "php_version" => PHP_VERSION, + "iconv_available" => function_exists("iconv"), + "intl_available" => class_exists("Transliterator"), + "curl_available" => function_exists("curl_init"), + "options_count" => count($this->getOptions()), + "active_mode" => $this->getOption("conversion_mode"), + "seo_enabled" => $this->getOption("enable_seo_optimization"), + "media_conversion" => $this->getOption("media_conversion_mode"), + "enabled_post_types" => $this->getOption("enabled_post_types"), + "enabled_taxonomies" => $this->getOption("enabled_taxonomies"), + ]; + + return $info; + } + + public function validateSystemRequirements() + { + $requirements = [ + "php_version" => version_compare(PHP_VERSION, "7.0", ">="), + "wordpress_version" => version_compare( + get_bloginfo("version"), + "5.0", + ">=" + ), + "mbstring_extension" => extension_loaded("mbstring"), + "json_extension" => extension_loaded("json"), + ]; + + return $requirements; + } + + public function isValidConfiguration() + { + $errors = $this->getConfigurationErrors(); + return empty($errors); + } + + public function getConfigurationErrors() + { + $options = $this->getOptions(); + + if (!$options["enable_conversion"]) { + return []; + } + + $errors = []; + + if (class_exists("WPSlug_Validator")) { + $api_validation = WPSlug_Validator::hasRequiredApiCredentials( + $options + ); + if ($api_validation !== true) { + $errors = array_merge($errors, $api_validation); + } + + $system_validation = WPSlug_Validator::validateSystemRequirements(); + if ($system_validation !== true) { + $errors = array_merge($errors, $system_validation); + } + } else { + if ($options["conversion_mode"] === "translation") { + $service = $options["translation_service"]; + if ( + $service === "google" && + empty($options["google_api_key"]) + ) { + $errors[] = __( + "Google API key is required for Google Translate service.", + "wpslug" + ); + } + if ( + $service === "baidu" && + (empty($options["baidu_app_id"]) || + empty($options["baidu_secret_key"])) + ) { + $errors[] = __( + "Baidu App ID and Secret Key are required for Baidu Translate service.", + "wpslug" + ); + } + } + + $requirements = $this->validateSystemRequirements(); + if (!$requirements["php_version"]) { + $errors[] = __("PHP 7.0 or higher is required.", "wpslug"); + } + if (!$requirements["wordpress_version"]) { + $errors[] = __( + "WordPress 5.0 or higher is required.", + "wpslug" + ); + } + if (!$requirements["mbstring_extension"]) { + $errors[] = __("PHP mbstring extension is required.", "wpslug"); + } + if (!$requirements["json_extension"]) { + $errors[] = __("PHP JSON extension is required.", "wpslug"); + } + } + + return $errors; + } +} \ No newline at end of file diff --git a/includes/class-wpslug-translator.php b/includes/class-wpslug-translator.php new file mode 100644 index 0000000..4c42775 --- /dev/null +++ b/includes/class-wpslug-translator.php @@ -0,0 +1,267 @@ +converter = null; + } + + public function translate($text, $options = array()) { + if (empty($text)) { + return ''; + } + + $service = isset($options['translation_service']) ? $options['translation_service'] : 'none'; + + switch ($service) { + case 'google': + return $this->translateGoogle($text, $options); + case 'baidu': + return $this->translateBaidu($text, $options); + case 'none': + default: + return $this->fallbackTranslate($text, $options); + } + } + + private function translateGoogle($text, $options) { + $api_key = isset($options['google_api_key']) ? trim($options['google_api_key']) : ''; + $source_lang = isset($options['translation_source_lang']) ? $options['translation_source_lang'] : 'auto'; + $target_lang = isset($options['translation_target_lang']) ? $options['translation_target_lang'] : 'en'; + + if (empty($api_key)) { + return $this->fallbackTranslate($text, $options); + } + + if (strlen($text) > 5000) { + return $this->fallbackTranslate($text, $options); + } + + try { + $url = 'https://translation.googleapis.com/language/translate/v2'; + $params = array( + 'key' => $api_key, + 'q' => $text, + 'source' => $source_lang, + 'target' => $target_lang, + 'format' => 'text' + ); + + $response = wp_remote_post($url, array( + 'timeout' => 15, + 'body' => $params, + 'headers' => array( + 'User-Agent' => 'WPSlug/' . WPSLUG_VERSION + ) + )); + + if (is_wp_error($response)) { + if (isset($options['debug_mode']) && $options['debug_mode']) { + error_log('WPSlug Google Translate Error: ' . $response->get_error_message()); + } + return $this->fallbackTranslate($text, $options); + } + + $response_code = wp_remote_retrieve_response_code($response); + if ($response_code !== 200) { + if (isset($options['debug_mode']) && $options['debug_mode']) { + error_log('WPSlug Google Translate HTTP Error: ' . $response_code); + } + return $this->fallbackTranslate($text, $options); + } + + $body = wp_remote_retrieve_body($response); + $data = json_decode($body, true); + + if (isset($data['data']['translations'][0]['translatedText'])) { + $translated = $data['data']['translations'][0]['translatedText']; + return $this->cleanTranslatedText($translated); + } + + return $this->fallbackTranslate($text, $options); + } catch (Exception $e) { + if (isset($options['debug_mode']) && $options['debug_mode']) { + error_log('WPSlug translateGoogle error: ' . $e->getMessage()); + } + return $this->fallbackTranslate($text, $options); + } + } + + private function translateBaidu($text, $options) { + $app_id = isset($options['baidu_app_id']) ? trim($options['baidu_app_id']) : ''; + $secret_key = isset($options['baidu_secret_key']) ? trim($options['baidu_secret_key']) : ''; + $source_lang = isset($options['translation_source_lang']) ? $options['translation_source_lang'] : 'auto'; + $target_lang = isset($options['translation_target_lang']) ? $options['translation_target_lang'] : 'en'; + + if (empty($app_id) || empty($secret_key)) { + return $this->fallbackTranslate($text, $options); + } + + if (strlen($text) > 6000) { + return $this->fallbackTranslate($text, $options); + } + + try { + $salt = wp_rand(10000, 99999); + $sign = md5($app_id . $text . $salt . $secret_key); + + $url = 'https://fanyi-api.baidu.com/api/trans/vip/translate'; + $params = array( + 'q' => $text, + 'from' => $source_lang, + 'to' => $target_lang, + 'appid' => $app_id, + 'salt' => $salt, + 'sign' => $sign + ); + + $response = wp_remote_post($url, array( + 'timeout' => 15, + 'body' => $params, + 'headers' => array( + 'User-Agent' => 'WPSlug/' . WPSLUG_VERSION + ) + )); + + if (is_wp_error($response)) { + if (isset($options['debug_mode']) && $options['debug_mode']) { + error_log('WPSlug Baidu Translate Error: ' . $response->get_error_message()); + } + return $this->fallbackTranslate($text, $options); + } + + $response_code = wp_remote_retrieve_response_code($response); + if ($response_code !== 200) { + if (isset($options['debug_mode']) && $options['debug_mode']) { + error_log('WPSlug Baidu Translate HTTP Error: ' . $response_code); + } + return $this->fallbackTranslate($text, $options); + } + + $body = wp_remote_retrieve_body($response); + $data = json_decode($body, true); + + if (isset($data['trans_result'][0]['dst'])) { + $translated = $data['trans_result'][0]['dst']; + return $this->cleanTranslatedText($translated); + } + + if (isset($data['error_code'])) { + if (isset($options['debug_mode']) && $options['debug_mode']) { + error_log('WPSlug Baidu Translate API Error: ' . $data['error_code']); + } + } + + return $this->fallbackTranslate($text, $options); + } catch (Exception $e) { + if (isset($options['debug_mode']) && $options['debug_mode']) { + error_log('WPSlug translateBaidu error: ' . $e->getMessage()); + } + return $this->fallbackTranslate($text, $options); + } + } + + private function fallbackTranslate($text, $options) { + if ($this->converter === null) { + $this->converter = new WPSlug_Converter(); + } + + $fallback_options = $options; + $fallback_options['conversion_mode'] = 'pinyin'; + + return $this->converter->convert($text, $fallback_options); + } + + private function cleanTranslatedText($text) { + $text = strip_tags($text); + $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + $text = preg_replace('/&.+?;/', '', $text); + $text = preg_replace('/[^a-zA-Z0-9\s\-_]/', '', $text); + $text = preg_replace('/\s+/', '-', $text); + $text = preg_replace('/\-+/', '-', $text); + $text = trim($text, '-_'); + + return $text; + } + + public function batchTranslate($items, $options = array()) { + $results = array(); + + if (!is_array($items)) { + return $results; + } + + foreach ($items as $item) { + try { + $translated = $this->translate($item, $options); + $results[] = array( + 'original' => $item, + 'translated' => $translated, + 'service' => isset($options['translation_service']) ? $options['translation_service'] : 'none' + ); + } catch (Exception $e) { + if (isset($options['debug_mode']) && $options['debug_mode']) { + error_log('WPSlug batchTranslate error: ' . $e->getMessage()); + } + $results[] = array( + 'original' => $item, + 'translated' => sanitize_title($item), + 'service' => 'fallback' + ); + } + } + + return $results; + } + + public function getSupportedServices() { + return array('none', 'google', 'baidu'); + } + + public function isServiceSupported($service) { + return in_array($service, $this->getSupportedServices()); + } + + public function isServiceConfigured($service, $options) { + switch ($service) { + case 'google': + return !empty($options['google_api_key']); + case 'baidu': + return !empty($options['baidu_app_id']) && !empty($options['baidu_secret_key']); + case 'none': + default: + return true; + } + } + + public function detectLanguage($text) { + if (preg_match('/[\x{4e00}-\x{9fff}]/u', $text)) { + return 'zh'; + } + if (preg_match('/[\x{0400}-\x{04ff}]/u', $text)) { + return 'ru'; + } + if (preg_match('/[\x{0590}-\x{05ff}]/u', $text)) { + return 'he'; + } + if (preg_match('/[\x{0600}-\x{06ff}]/u', $text)) { + return 'ar'; + } + if (preg_match('/[\x{3040}-\x{309f}]/u', $text)) { + return 'ja'; + } + if (preg_match('/[\x{30a0}-\x{30ff}]/u', $text)) { + return 'ja'; + } + if (preg_match('/[\x{ac00}-\x{d7af}]/u', $text)) { + return 'ko'; + } + + return 'en'; + } +} \ No newline at end of file diff --git a/includes/class-wpslug-transliterator.php b/includes/class-wpslug-transliterator.php new file mode 100644 index 0000000..8375ab4 --- /dev/null +++ b/includes/class-wpslug-transliterator.php @@ -0,0 +1,200 @@ +initCharMaps(); + } + + public function transliterate($text, $options = array()) { + if (empty($text)) { + return ''; + } + + $method = isset($options['transliteration_method']) ? $options['transliteration_method'] : 'basic'; + + switch ($method) { + case 'iconv': + return $this->transliterateIconv($text, $options); + case 'intl': + return $this->transliterateIntl($text, $options); + case 'basic': + default: + return $this->transliterateBasic($text, $options); + } + } + + private function transliterateBasic($text, $options) { + $text = $this->applyCharMaps($text); + $text = $this->cleanSlug($text); + + if (isset($options['force_lowercase']) && $options['force_lowercase']) { + $text = strtolower($text); + } + + return $text; + } + + private function transliterateIconv($text, $options) { + if (!function_exists('iconv')) { + return $this->transliterateBasic($text, $options); + } + + try { + $text = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $text); + $text = $this->cleanSlug($text); + + if (isset($options['force_lowercase']) && $options['force_lowercase']) { + $text = strtolower($text); + } + + return $text; + } catch (Exception $e) { + return $this->transliterateBasic($text, $options); + } + } + + private function transliterateIntl($text, $options) { + if (!class_exists('Transliterator')) { + return $this->transliterateIconv($text, $options); + } + + try { + $transliterator = Transliterator::create('Any-Latin; Latin-ASCII'); + if ($transliterator) { + $text = $transliterator->transliterate($text); + $text = $this->cleanSlug($text); + + if (isset($options['force_lowercase']) && $options['force_lowercase']) { + $text = strtolower($text); + } + + return $text; + } + } catch (Exception $e) { + if (isset($options['debug_mode']) && $options['debug_mode']) { + error_log('WPSlug transliterateIntl error: ' . $e->getMessage()); + } + } + + return $this->transliterateIconv($text, $options); + } + + private function applyCharMaps($text) { + foreach ($this->char_maps as $from => $to) { + $text = str_replace($from, $to, $text); + } + return $text; + } + + private function cleanSlug($text) { + $text = strip_tags($text); + $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + $text = preg_replace('/&.+?;/', '', $text); + $text = preg_replace('/[^a-zA-Z0-9\s\-_]/', '', $text); + $text = preg_replace('/\s+/', '-', $text); + $text = preg_replace('/\-+/', '-', $text); + $text = trim($text, '-_'); + + return $text; + } + + private function initCharMaps() { + $this->char_maps = array( + 'А' => 'A', 'а' => 'a', 'Б' => 'B', 'б' => 'b', 'В' => 'V', 'в' => 'v', + 'Г' => 'G', 'г' => 'g', 'Д' => 'D', 'д' => 'd', 'Е' => 'E', 'е' => 'e', + 'Ё' => 'Yo', 'ё' => 'yo', 'Ж' => 'Zh', 'ж' => 'zh', 'З' => 'Z', 'з' => 'z', + 'И' => 'I', 'и' => 'i', 'Й' => 'J', 'й' => 'j', 'К' => 'K', 'к' => 'k', + 'Л' => 'L', 'л' => 'l', 'М' => 'M', 'м' => 'm', 'Н' => 'N', 'н' => 'n', + 'О' => 'O', 'о' => 'o', 'П' => 'P', 'п' => 'p', 'Р' => 'R', 'р' => 'r', + 'С' => 'S', 'с' => 's', 'Т' => 'T', 'т' => 't', 'У' => 'U', 'у' => 'u', + 'Ф' => 'F', 'ф' => 'f', 'Х' => 'H', 'х' => 'h', 'Ц' => 'C', 'ц' => 'c', + 'Ч' => 'Ch', 'ч' => 'ch', 'Ш' => 'Sh', 'ш' => 'sh', 'Щ' => 'Shh', 'щ' => 'shh', + 'Ъ' => '', 'ъ' => '', 'Ы' => 'Y', 'ы' => 'y', 'Ь' => '', 'ь' => '', + 'Э' => 'E', 'э' => 'e', 'Ю' => 'Yu', 'ю' => 'yu', 'Я' => 'Ya', 'я' => 'ya', + + 'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ß' => 'ss', + 'Ä' => 'Ae', 'Ö' => 'Oe', 'Ü' => 'Ue', + + 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a', 'å' => 'a', + 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A', + 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e', + 'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', + 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', + 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I', + 'ò' => 'o', 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ø' => 'o', + 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' => 'O', 'Ø' => 'O', + 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ü' => 'u', + 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', + 'ý' => 'y', 'ÿ' => 'y', 'Ý' => 'Y', 'Ÿ' => 'Y', + 'ñ' => 'n', 'Ñ' => 'N', + 'ç' => 'c', 'Ç' => 'C', + 'æ' => 'ae', 'Æ' => 'AE', + 'œ' => 'oe', 'Œ' => 'OE', + + 'ā' => 'a', 'ē' => 'e', 'ī' => 'i', 'ō' => 'o', 'ū' => 'u', + 'Ā' => 'A', 'Ē' => 'E', 'Ī' => 'I', 'Ō' => 'O', 'Ū' => 'U', + + 'ą' => 'a', 'ć' => 'c', 'ę' => 'e', 'ł' => 'l', 'ń' => 'n', + 'ó' => 'o', 'ś' => 's', 'ź' => 'z', 'ż' => 'z', + 'Ą' => 'A', 'Ć' => 'C', 'Ę' => 'E', 'Ł' => 'L', 'Ń' => 'N', + 'Ó' => 'O', 'Ś' => 'S', 'Ź' => 'Z', 'Ż' => 'Z', + + 'ă' => 'a', 'î' => 'i', 'ș' => 's', 'ț' => 't', + 'Ă' => 'A', 'Î' => 'I', 'Ș' => 'S', 'Ț' => 'T', + + 'α' => 'a', 'β' => 'b', 'γ' => 'g', 'δ' => 'd', 'ε' => 'e', + 'ζ' => 'z', 'η' => 'i', 'θ' => 'th', 'ι' => 'i', 'κ' => 'k', + 'λ' => 'l', 'μ' => 'm', 'ν' => 'n', 'ξ' => 'x', 'ο' => 'o', + 'π' => 'p', 'ρ' => 'r', 'σ' => 's', 'τ' => 't', 'υ' => 'y', + 'φ' => 'f', 'χ' => 'ch', 'ψ' => 'ps', 'ω' => 'o', + 'Α' => 'A', 'Β' => 'B', 'Γ' => 'G', 'Δ' => 'D', 'Ε' => 'E', + 'Ζ' => 'Z', 'Η' => 'I', 'Θ' => 'TH', 'Ι' => 'I', 'Κ' => 'K', + 'Λ' => 'L', 'Μ' => 'M', 'Ν' => 'N', 'Ξ' => 'X', 'Ο' => 'O', + 'Π' => 'P', 'Ρ' => 'R', 'Σ' => 'S', 'Τ' => 'T', 'Υ' => 'Y', + 'Φ' => 'F', 'Χ' => 'CH', 'Ψ' => 'PS', 'Ω' => 'O', + + 'ã' => 'a', 'õ' => 'o', 'ç' => 'c', + 'Ã' => 'A', 'Õ' => 'O', 'Ç' => 'C', + + 'ğ' => 'g', 'ı' => 'i', 'ş' => 's', 'ü' => 'u', 'ö' => 'o', 'ç' => 'c', + 'Ğ' => 'G', 'İ' => 'I', 'Ş' => 'S', 'Ü' => 'U', 'Ö' => 'O', 'Ç' => 'C', + + 'ک' => 'k', 'گ' => 'g', 'چ' => 'ch', 'پ' => 'p', 'ژ' => 'zh', + 'ی' => 'y', 'ء' => 'a', 'ؤ' => 'w', 'ئ' => 'y', 'ة' => 'h', + 'ا' => 'a', 'ب' => 'b', 'ت' => 't', 'ث' => 'th', 'ج' => 'j', + 'ح' => 'h', 'خ' => 'kh', 'د' => 'd', 'ذ' => 'dh', 'ر' => 'r', + 'ز' => 'z', 'س' => 's', 'ش' => 'sh', 'ص' => 's', 'ض' => 'd', + 'ط' => 't', 'ظ' => 'dh', 'ع' => 'a', 'غ' => 'gh', 'ف' => 'f', + 'ق' => 'q', 'ل' => 'l', 'م' => 'm', 'ن' => 'n', 'ه' => 'h', + 'و' => 'w', 'ي' => 'y' + ); + } + + public function getSupportedMethods() { + return array('basic', 'iconv', 'intl'); + } + + public function isMethodSupported($method) { + return in_array($method, $this->getSupportedMethods()); + } + + public function getAvailableMethods() { + $methods = array('basic'); + + if (function_exists('iconv')) { + $methods[] = 'iconv'; + } + + if (class_exists('Transliterator')) { + $methods[] = 'intl'; + } + + return $methods; + } +} \ No newline at end of file diff --git a/includes/class-wpslug-validator.php b/includes/class-wpslug-validator.php new file mode 100644 index 0000000..ba32bbc --- /dev/null +++ b/includes/class-wpslug-validator.php @@ -0,0 +1,193 @@ + $max) { + return $max; + } + + return $int_value; + } + + public static function validateString($value, $max_length = 200) { + $string_value = sanitize_text_field($value); + + if (strlen($string_value) > $max_length) { + return substr($string_value, 0, $max_length); + } + + return $string_value; + } + + public static function validateTextarea($value) { + return sanitize_textarea_field($value); + } + + public static function validateArray($value, $default = array()) { + if (!is_array($value)) { + return $default; + } + + $sanitized = array_map('sanitize_text_field', $value); + $filtered = array_filter($sanitized); + + return array_slice($filtered, 0, 50); + } + + public static function validateSelect($value, $valid_options, $default) { + return in_array($value, $valid_options, true) ? $value : $default; + } + + public static function validateApiKey($value) { + return self::validateString($value, 200); + } + + public static function validateSlug($slug) { + if (empty($slug)) { + return false; + } + + if (strlen($slug) > 200) { + return false; + } + + if (preg_match('/[^a-zA-Z0-9\-_\p{Han}]/u', $slug)) { + return false; + } + + return true; + } + + public static function validateLanguageCode($code) { + $valid_codes = array( + 'auto', 'zh', 'zh-TW', 'en', 'es', 'fr', 'de', 'ja', 'ko', 'ru', + 'ar', 'it', 'pt', 'nl', 'pl', 'tr', 'sv', 'da', 'no', 'fi', 'cs', + 'hu', 'ro', 'bg', 'hr', 'sk', 'sl', 'et', 'lv', 'lt', 'mt', 'el', 'cy' + ); + + return in_array($code, $valid_codes, true) ? $code : 'auto'; + } + + public static function validatePostTypes($post_types) { + if (!is_array($post_types)) { + return array('post', 'page'); + } + + $all_post_types = get_post_types(array('public' => true)); + $validated = array(); + + foreach ($post_types as $post_type) { + if (in_array($post_type, $all_post_types)) { + $validated[] = $post_type; + } + } + + return empty($validated) ? array('post', 'page') : $validated; + } + + public static function validateTaxonomies($taxonomies) { + if (!is_array($taxonomies)) { + return array('category', 'post_tag'); + } + + $all_taxonomies = get_taxonomies(array('public' => true)); + $validated = array(); + + foreach ($taxonomies as $taxonomy) { + if (in_array($taxonomy, $all_taxonomies)) { + $validated[] = $taxonomy; + } + } + + return empty($validated) ? array('category', 'post_tag') : $validated; + } + + public static function validateConversionMode($mode) { + $valid_modes = array('pinyin', 'transliteration', 'translation'); + return self::validateSelect($mode, $valid_modes, 'pinyin'); + } + + public static function validateTranslationService($service) { + $valid_services = array('none', 'google', 'baidu'); + return self::validateSelect($service, $valid_services, 'none'); + } + + public static function validateTransliterationMethod($method) { + $valid_methods = array('basic', 'iconv', 'intl'); + return self::validateSelect($method, $valid_methods, 'basic'); + } + + public static function hasRequiredApiCredentials($options) { + $errors = array(); + + if ($options['conversion_mode'] === 'translation') { + $service = $options['translation_service']; + + if ($service === 'google' && empty($options['google_api_key'])) { + $errors[] = __('Google API key is required for Google Translate service.', 'wpslug'); + } + + if ($service === 'baidu' && (empty($options['baidu_app_id']) || empty($options['baidu_secret_key']))) { + $errors[] = __('Baidu App ID and Secret Key are required for Baidu Translate service.', 'wpslug'); + } + } + + return empty($errors) ? true : $errors; + } + + public static function validateSystemRequirements() { + $requirements = array( + 'php_version' => version_compare(PHP_VERSION, '7.0', '>='), + 'wordpress_version' => version_compare(get_bloginfo('version'), '5.0', '>='), + 'mbstring_extension' => extension_loaded('mbstring'), + 'json_extension' => extension_loaded('json') + ); + + $errors = array(); + + if (!$requirements['php_version']) { + $errors[] = __('PHP 7.0 or higher is required.', 'wpslug'); + } + + if (!$requirements['wordpress_version']) { + $errors[] = __('WordPress 5.0 or higher is required.', 'wpslug'); + } + + if (!$requirements['mbstring_extension']) { + $errors[] = __('PHP mbstring extension is required.', 'wpslug'); + } + + if (!$requirements['json_extension']) { + $errors[] = __('PHP JSON extension is required.', 'wpslug'); + } + + return empty($errors) ? true : $errors; + } +} \ No newline at end of file diff --git a/includes/dictionary.php b/includes/dictionary.php new file mode 100644 index 0000000..9ec74e9 --- /dev/null +++ b/includes/dictionary.php @@ -0,0 +1,419 @@ + '啊嗄锕阿', + 'Ai' => '㕌㗒㘷㝶㢊㤅㱯㶼㾢㿄䀳䅬䑂䔽䝽䠹䨠䶣伌僾凒叆哀哎唉啀嗌嗳嘊噯埃塧壒娭娾嫒嬡愛懓懝挨捱敱敳昹暧曖欸毐溰溾濭爱瑷璦癌皑皚皧瞹矮砹硋碍礙艾蔼薆藹譪譺躷銰鎄鑀锿閡隘霭靄靉餲馤騃鱫鴱𣝅', + 'An' => '㛺㜝㞄㟁㫨㱘㸩㽢䀂䅁䅖䜙䢿䬓䮗䯥侒俺儑唵啽垵埯堓婩媕安岸峖庵按揞晻暗案桉氨洝犴玵痷盦盫罯胺腤荌菴萻葊蓭誝諳谙豻貋銨錌铵闇隌雸鞌鞍韽馣鮟鵪鶕鹌黯𩽾', + 'Ang' => '㭿㼜䀚䇦䒢䩕䭹䭺卬岇昂昻枊盎肮醠骯', + 'Ao' => '㑃㕭㘬㘭㜜㜩㟼㠂㠗㤇㥿㩠㿰䐿䜒䥝䦋䫜䫨䮯䯠䴈䵅傲凹厫嗷嗸坳垇墺奡奥奧媪媼嫯岙岰嶅嶴廒慠懊扷抝拗摮擙敖柪梎滶澳熬爊獒獓璈磝翱翶翺聱芺蔜螯袄襖謷謸軪遨鏊鏖镺隞隩驁骜鰲鳌鷔鼇𦪈𩼈', + 'Ba' => '㔜㞎㭭㶚㸭㺴㿬䃻䆉䇑䎬䎱䟦䩗䩻䮂䰾䳊䶕丷仈八叐叭吧哵坝坺垻墢壩夿妭岜峇巴巼弝扒把抜拔捌朳柭欛灞炦爸犮玐疤癹矲笆粑紦罢罷羓耙胈芭茇菝蚆覇詙豝跁跋軷釛釟鈀钯霸靶颰魃魞鮊鲃鲅鲌鼥𩨜', + 'Bai' => '㓦㔥㗑㠔㿟䒔䙓䢙䪹䳆佰庍拜拝挀捭掰摆擘擺敗柏栢猈瓸白百稗竡粨粺絔薭襬贁败韛𡏯𣺽', + 'Ban' => '㚘㪵䃑䈲䉽䬳伴办半坂坢姅岅怑扮扳拌搬攽斑斒昄板柈湴版班瓣瓪瘢癍秚粄絆绊舨般蝂螁螌褩辦辬鈑鉡钣闆阪靽頒颁魬鳻', + 'Bang' => '㙃㨍㭋㮄㿶䂜䎧䖫䧛䩷䰷傍垹塝帮幇幚幫捠搒梆棒棓榜浜牓玤磅稖綁縍绑膀艕蒡蚌蜯謗谤邦邫鎊镑鞤髈𠳐𢜗𢶶', + 'Bao' => '㙅㙸㫧㲒㵡㻄㿺䈏䎂䤖䥤䨌䨔䪨䭋䳈䳰䴐佨保儤勹勽包堡堢報媬嫑孢宝宲寚寳寶忁怉报抱暴曓枹煲爆珤窇笣緥胞苞菢葆蕔薄藵虣蚫袌褒褓襃豹賲趵鉋鑤铇闁雹靌靤飹飽饱駂骲髱鮑鲍鳵鴇鸨齙龅', + 'Bei' => '㔨㗗㛝㣁㤳㫲㰆㶔㷶㸢㸬㸽㻗㽡㾱䋳䔒䟺䡶䥯䩀䰽俻倍偝偹備僃北卑呗唄备孛悖悲惫愂憊揹昁杯桮梖椑焙牬犕狈狽珼琲盃碑碚禙糒背苝蓓藣蛽被褙誖貝贝軰輩辈邶郥鄁鉳鋇鐾钡陂鞁鞴骳鵯鹎', + 'Ben' => '㡷㤓㨧㮥㮺䬱倴坋坌奔奙捹撪本栟桳楍泍渀犇獖畚笨翉苯贲輽逩錛锛', + 'Beng' => '㑟㔙㷯䋽䑫䙀䨜䨻䩬䭰䳞伻傰嘣埄埲塴奟崩嵭揼泵琣琫甏甭痭祊絣綳繃绷菶蹦迸逬鏰镚閍鞛𥞩𧚭', + 'Bi' => '㓖㘠㘩㙄㠲㡀㡙㢰㢶㢸㧙㪏㪤㮿㯇㱸㳼㵥㻫㻶㿫䀣䁹䃾䄶䉾䊧䋔䎵䏢䏶䕗䖩䘡䚜䟆䟤䠋䣥䧗䨆䩛䪐䫁䫾䬛䮠䮡䯗䵄佊佖俾偪匕吡哔啚嗶坒堛壁夶奰妣妼婢嬖嬶屄币幣幤庇庳廦弊弻弼彃彼必怭怶愊愎敝斃朼枈柀柲梐楅榌比毕毖毙毴沘湢滗滭潷濞煏熚狴獘獙珌璧畀畁畢疕疪痹痺皕睤碧禆秕笓笔筆筚箄箅箆篦篳粃粊綼縪繴罼聛腷臂舭苾荜荸萆萞蓖蓽蔽薜蜌螕袐裨襅襞襣觱詖诐豍貏貱賁贔赑跸蹕躃躄逼避邲鄙鄨鄪鉍鎞鏎鐴铋閇閉閟闭陛鞸韠飶饆馝駜驆髀髲魓鮅鰏鲾鵖鷝鷩鼊鼻', + 'Bian' => '㝸㣐㦚㭓㲢㳎㳒㴜㵷㺹䁵䉸䒪䛒䟍䡢䪻便匾卞变変峅弁徧忭惼扁抃揙昪汳汴炞煸牑猵獱玣甂砭碥稨窆笾箯籩糄編緶缏编艑苄萹藊蝙褊覍變貶贬辡辧辨辩辫辮辯边辺遍邉邊釆鍽閞鞭鯾鯿鳊鴘', + 'Biao' => '㟽㠒㧼㯹㶾䁃䁭䅺䔸䙳䞄䮽俵儦墂婊幖彪摽杓标標檦淲滮瀌灬熛爂猋瘭磦穮脿膘臕蔈藨表裱褾諘謤贆錶鏢鑣镖镳颩颮颷飆飇飈飊飑飙飚驃驫骉骠髟鰾鳔', + 'Bie' => '㔡㢼㿜䇷䋢䌘䏟䘷䠥䭱䳤別别咇彆徶憋瘪癟莂虌蛂蟞襒蹩鱉鳖鼈龞', + 'Bin' => '㻞䐔䚔䧬䨈傧儐宾彬摈擯斌梹椕槟檳殡殯氞汃滨濒濱濵瀕玢瑸璸砏繽缤膑臏虨豩豳賓賔邠鑌镔霦顮髌髕髩鬂鬓鬢', + 'Bing' => '㓈㨀䔊䗒䴵丙並仌仒併倂偋傡兵冫冰垪寎并幷庰怲抦掤摒昞昺柄栤棅氷炳病眪禀秉稟窉竝苪蛃誁邴鈵鉼鋲陃靐鞆鞞餅餠饼鮩', + 'Bo' => '㗘㝿㞈㟑㩧㩭㪍㬍㬧㴾㶿㹀㼎㼟㼣䂍䃗䊿䌟䍸䑈䗚䙏䝛䞳䟛䢌䢪䥬䪇䪬䬪䭦䭯䮀䯋䰊䳁䵗䶈亳仢伯侼僠僰剝剥勃博卜哱啵嚗孹嶓帗帛愽懪拨挬搏撥播檗欂波浡淿渤溊煿牔犦犻狛猼玻瓝瓟癶癷盋砵碆礡礴秡箔箥簙簸糪紴缽肑胉脖膊舶艊苩菠萡葧蔔蘗袚袯袰袹襏襮譒豰跛踣蹳郣鈸鉑鉢鋍鎛鑮钵钹铂镈餑餺饽馎馛馞駁駮驋驳髆髉鮁鱍鵓鹁', + 'Bu' => '㘵㙛㚴㨐㳍㻉㾟䀯䊇䋠䍌䏽䑰䒀䝵䪁䪔䬏䴺不佈勏卟吥咘哺喸埔埗埠峬布庯廍怖悑抪捕捗晡柨步歨歩瓿篰簿荹蔀补補誧踄轐逋部郶醭鈽钚钸餔餢鳪鵏鸔', + 'Ca' => '䃰䌨䵽嚓囃擦攃礤礸遪𨆾', + 'Cai' => '㒲㥒䌽䐆䞗䟀䠕䣋䰂䴭倸偲啋埰婇寀彩才採材棌毝猜睬綵縩纔菜蔡裁財财跴踩采', + 'Can' => '㛑㜗㣓㥇㦧㨻㱚㻮㽩㿊䅟䉔䏼䗝䗞䘉䙁䛹䝳䟃䣟䱗䳻傪儏参參叄叅喰嬠孱惨惭慘慙慚憯掺摻朁残殘湌澯灿燦爘璨穇篸粲薒蚕蝅蠶蠺謲飡餐驂骖黪黲', + 'Cang' => '㵴㶓䅮䢢仓仺伧倉傖嵢欌沧滄濸獊舱艙苍蒼藏螥賶鑶鶬鸧', + 'Cao' => '㜖㯥䄚䎭䏆䐬䒃䒑嘈嶆愺懆撡操曹曺槽漕糙肏艚艸艹草蓸螬褿襙鄵鏪騲𥕢', + 'Ce' => '㥽㨲㩍䇲䈟䊂䔴侧側冊册厕厠墄廁恻惻憡拺敇测測畟笧策筞筴箣簎粣荝萗萴蓛', + 'Cen' => '㞥䅾䤁䨙䲋岑嵾梣涔笒𩻛', + 'Ceng' => '㣒㬝䁬䉕噌层層嶒曽曾竲蹭驓', + 'Cha' => '㛼㢉㢒㣾㤞㪯㫅㮑䁟䅊䒲䓭䕓䟕䡨䤩䶪侘偛叉嗏垞奼姹察岔嵖差扠挿插揷搽杈查槎檫汊猹疀碴秅紁肞臿艖茬茶衩詧詫诧蹅銟鍤鑔锸镲靫餷馇', + 'Chai' => '㑪㳗㼮㾹䐤䓱䘍䜺侪儕喍囆拆柴犲瘥祡芆茝虿蠆袃訍豺釵钗齜', + 'Chan' => '㙴㙻㚲㢆㢟㤐㦃㬄㯆㰫㶣㸥㹌㹽㺗㺥䀡䂁䊲䐮䑎䜛䠨䡲䣑䤘䤫䥀䧯䩶䪜䫮䱿䴼䵐丳产僝儃儳冁刬剗剷劖啴嘽嚵囅壥婵嬋嵼巉幝幨廛忏懴懺搀摌摲攙斺旵梴棎欃毚浐湹滻潹潺澶瀍瀺灛煘燀獑產産硟磛禅禪簅緾繟纏纒缠羼艬蒇蕆蝉蟬蟾裧襜覘觇誗諂譂讇讒谄谗躔辴辿鄽酁鉆鋋鋓鏟鑱铲镡镵閳闡阐韂顫颤饞馋骣𬊤', + 'Chang' => '㙊㦂㫤䅛䗅䗉䠆䩨䮖䯴仧仩伥倀倡偿僘償兏厂厰唱嘗嚐场場塲娼嫦尝常廠徜怅悵惝敞昌昶晿暢椙氅淐焻猖玚琩瑒瑺瓺甞畅畼肠腸膓苌菖萇蟐裮誯鋹鋿錩鏛锠镸閶阊韔鬯鯧鱨鲳鲿鼚', + 'Chao' => '㶤㷅䎐䏚䜈䫸䫿䰫仦仯勦吵嘲巐巢巣弨怊抄晁朝樔欩漅潮炒焣焯煼牊眧窲罺耖觘訬謿超轈鄛鈔钞麨鼂鼌𠰉', + 'Che' => '㒤㔭㤴㥉㨋㬚㳧㵔㾝㿭䁤䋲䒆䚢䛸䜠䞣䧪䰩伡俥偖勶唓坼屮彻徹扯掣撤撦澈烢爡瞮砗硨硩聅莗蛼車车迠頙𤥭', + 'Chen' => '㕴㥲㧱㫳㴴㽸䀼䆣䐜䑣䒞䜟䞋䟢䠳䢅䢈䢻䣅䤟䫈䫖儭嗔嚫塵墋夦宸尘忱愖抻捵揨敐晨曟榇樄櫬沈沉煁琛疢瘎瞋硶碜磣綝縝臣茞莀莐蔯薼螴衬襯訦諃諶謓讖谌谶賝贂趁趂趻踸軙辰迧郴醦鈂鍖陈陳霃鷐麎齓齔龀𧿒𬘭', + 'Cheng' => '㐼㓌㛵㞼㲂㼩䁎䄇䆑䆵䇸䕝䗀䚘䞓䟓䟫䧕䫆䮪丞乗乘侱偁僜呈城埕堘塍塖娍宬峸庱徎悜惩憆憕懲成承挰掁摚撐撑晟朾枨柽棖棦椉橕橙檉檙泟洆浾湞溗澂澄瀓爯牚珵珹琤畻睈瞠碀秤称程稱穪窚竀筬絾緽罉脀脭荿蛏蟶裎誠诚赪赬逞郕酲鋮鏳鏿鐣铖阷靗頳饓騁騬骋鯎𨁎', + 'Chi' => '㒆㓼㔑㘜㙜㞴㞿㡿㢁㢋㢮㥡㮛㰞㱀㶴㷰㺈㽚䀸䇪䊼䑛䙙䜄䜉䜵䜻䞾䟷䠠䤲䧝䪧䮈䮻䰡䳵䶔䶵侈侙傺勅勑卶叱叺吃呎哧啻喫嗤噄坻垑墀妛媸尺岻弛彨彲彳恜恥慗憏懘抶持摛攡敕斥杘欼歭歯池湁漦灻炽烾熾瓻痓痴痸瘈瘛癡眵瞝硳竾笞筂箎篪粚絺翄翅翤翨耻肔胣胵腟茌荎蚇蚩蚳螭袲袳裭褫訵誺謘貾赤赿趍趩跮踟迟遅遟遫遲鉓鉹銐雴飭饎饬馳驰魑鴟鵄鶒鷘鸱麶黐齒齝齿', + 'Chong' => '㓽㤝㧤㮔㳘㹐䂌䆔䆹䌬䖝䘪䝑䡴䳯充冲嘃埫宠寵崇崈徸忡憃憧揰摏沖浺爞珫緟罿翀舂艟茺虫蝩蟲衝褈蹖銃铳隀', + 'Chou' => '㐜㤽㦞㨨㮲㵞㿧䀺䌧䌷䓓䔏䪮䲖丑丒仇侴俦偢儔吜嚋婤嬦帱幬怞惆愁懤抽搊杻杽栦椆殠燽犨犫畴疇瘳皗瞅矁稠筹篘籌紬絒綢绸臭臰菗薵裯讎讐踌躊遚酧酬醜醻雔雠魗', + 'Chu' => '㔘㕏㕑㗙㙇㛀㡡㤕㾥䅳䇍䊰䎌䎝䐍䖏䙘䜴䝙䟞䟣䠂䠧䢺䦌亍俶傗储儊儲処出刍初厨嘼埱处媰岀幮廚怵憷拀搐摴敊斶杵柷椘楚楮榋樗橱橻檚櫉櫥欪歜滀滁濋犓珿琡璴畜矗础礎竌竐篨絀绌耡臅芻蒢蒭蓫蕏藸處蜍蟵褚触觸諔豖豠貙趎踀蹰躇躕鄐鉏鋤锄閦除雏雛鶵黜齣齭齼𢊍𤝞𧎷𨃕𬺓', + 'Chua' => '㔍䊬䫄䵵欻歘', + 'Chuai' => '㪓㪜䦤䦷䴝啜嘬揣搋膗膪踹', + 'Chuan' => '㯌㱛㼷䁣串传傳僢剶喘圌巛川暷椽歂氚汌猭玔瑏穿篅舛舡舩船荈賗踳輲遄釧钏鶨', + 'Chuang' => '㡖㼽䃥䄝䆫䎫䚒䭚傸凔刅创刱剏剙創噇幢床怆愴摐摤牀牎牕疮瘡磢窓窗窻闖闯𠳹', + 'Chui' => '㝽㷃䍋䞼倕吹垂埀捶搥棰椎槌炊箠腄菙錘鎚锤陲顀龡', + 'Chun' => '㖺㝄㝇㵮㸪㿤䏛䐏䓐䔚䞐䞺䡅䣨䣩䥎䦮䫃䮞䲠偆唇堾媋惷旾春暙杶椿槆橁櫄浱淳湻滣漘犉瑃睶箺純纯脣莼萅萶蒓蓴蝽蠢賰輴醇醕錞陙鯙鰆鶉鶞鹑𬭚', + 'Chuo' => '㚟㪬㲋䋘䓎嚽娕娖婼惙戳擉歠涰磭綽繛绰腏趠踔輟辍辵辶逴酫鑡齪龊', + 'Ci' => '㓨㘂㘹㞖㢀㤵㩞䂣䈘䓧䗹䛐䧳䨏䭣䯸䰍䲿䳄䳐伺佌佽偨刺刾呲垐堲嬨庛慈朿柌栨次此泚濨玼珁瓷甆疵皉磁礠祠糍絘縒茈茦茨莿薋蛓螆蠀詞词賜赐趀跐辝辞辤辭雌飺餈骴髊鮆鴜鶿鷀鹚齹', + 'Cong' => '㗰㜡㞱㥖㼻䈡䉘䐋䐫䓗䕺䗓䡯䢨䳷丛从匆叢囪囱婃孮従徖從忩怱悤悰慒憁暰枞棇樅樬樷欉淙漎漗潀潨灇焧熜爜琮瑽璁瞛篵緫繱聡聦聪聰苁茐葱蓯蔥藂蟌誴謥賨賩鍯鏦騘驄骢', + 'Cou' => '凑湊腠輳辏', + 'Cu' => '㗤䃚䙯䛤䟟䠞䢐䣯䥄䥘促噈媨徂憱殂猝瘄瘯簇粗縬脨蔟觕誎趗踧蹙蹴蹵酢醋顣麁麄麤鼀𥾛', + 'Cuan' => '㠝㸑巑撺攛櫕欑殩汆熶爨穳窜竄篡簒蹿躥鋑鑹镩', + 'Cui' => '㜠㝮㯔㯜㱖㳃㵏㷪䃀䄟䆊䊫䙑䧽乼伜倅催凗啐啛墔崔嶉忰悴慛摧榱槯毳淬漼濢焠獕璀疩瘁皠磪竁粋粹紣綷縗缞翆翠脃脆脺膬膵臎萃襊趡鏙顇', + 'Cun' => '䍎䞭侟刌吋存寸忖拵村澊皴竴籿膥踆邨', + 'Cuo' => '㟇㭫㽨㿷䂳䑘䠡䣜䰈䱜䴾剉剒厝夎嵯嵳挫措搓撮斮棤瑳痤睉矬磋脞莝莡蒫蓌蔖虘蹉躦逪遳酂醝銼錯锉错鹺鹾', + 'Da' => '㙮㜓㟷㩉㾑㿯㿴䃮䌋䐛䪚䵣亣剳匒呾咑哒嗒噠垯墶大妲怛打搭撘汏沓炟燵畗畣瘩眔笚笪答繨羍耷荅荙薘蟽褡詚跶躂达迏迖迚逹達鎉鎝鐽阘靼鞑韃龖龘', + 'Dai' => '㐲㞭㯂㶡㻖䈆䒫䚞䚟䲦代侢傣叇呆呔垈埭岱帒带帯帶廗待怠懛戴曃柋歹殆瀻獃玳瑇甙簤紿緿绐艜蚮袋襶貸贷蹛軑軚軩轪迨逮霴靆骀鮘鴏黛黱', + 'Dan' => '㐤㕪㗖㠆㡺㲷㴷䃫䄡䉞䐷䒟䨢䨵䩥䭛䳉丹亶伔但僤儋刐勯匰单単啖啗啿單嘾噉嚪妉媅帎弹弾彈惮憚憺抌担掸撢撣擔旦柦殚殫氮沊泹淡澸澹狚玬瓭甔疍疸瘅癉癚眈砃禫窞箪簞紞繵耼耽聃聸胆腅膽萏蓞蛋蜑衴褝襌觛誕诞贉赕躭郸鄲霮頕饏馾駳髧鴠黕黮𣛱𧂄𫢸𬘘', + 'Dang' => '㼕㽆䑗䣊䣣䦒儅党凼噹圵垱壋婸宕嵣当愓挡擋攩档檔欓氹潒澢灙珰璗璫瓽當盪瞊砀碭礑筜簜簹艡荡菪蕩蘯蟷裆襠譡讜谠趤逿鐺铛闣雼黨', + 'Dao' => '㠀㨶㿒䆃䊭䌦䧂倒刀刂到叨噵壔导導岛島嶋嶌嶹忉悼捣捯搗擣朷椡槝檤氘焘燾瓙盗盜祷禂禱稲稻箌纛翢翿舠艔菿衜衟蹈軇道釖陦隝隯魛鱽', + 'De' => '㝵㤫㥁㯖䙷䙸嘚地得徳德恴悳惪棏淂的脦鍀锝𠵨', + 'Den' => '㩐扥扽', + 'Deng' => '㔁㲪䒭䔲䙞䠬䮴䳾凳噔墱嬁嶝戥朩櫈灯燈璒登瞪磴竳等簦艠覴豋蹬邓鄧鐙镫隥𤮘', + 'Di' => '㓳㢩㣙㪆㫝㭽㰅㹍㼵䀿䂡䃅䊮䍕䏄䏑䐎䑭䑯䗖䢑䣌䧑䨀䨤䩘䩚䯼䴞䵠䶍仾低俤偙僀厎呧唙啇啲嘀嚁坔坘埊埞堤墑墬奃娣媂嫡嶳帝底廸弟弤彽怟慸抵拞掋摕敌敵旳杕枤柢梊梑棣樀氐涤渧滌滴焍牴狄玓珶甋眱睇砥碲磾祶禘笛第篴籴糴締缔羝翟聜腣苖荻菂菧蒂蔋蔐蔕藡蝃螮袛覿觌觝詆諦诋谛豴趆踶蹢軧迪递逓遞遰邸釱鉪鍉鏑镝阺隄靮鞮頔馰骶髢鬄鯳鸐', + 'Dian' => '㓠㝪㞟㶘㸃㼭䍄䓦佃傎典厧嚸坫垫墊壂奌奠婝婰嵮巅巓巔店惦扂掂攧敁敟椣槇槙橂橝殿淀滇澱点猠玷琔电甸瘨癜癫癲碘簟蒧蕇蜔跕踮蹎钿阽電靛顚顛颠驔點齻', + 'Diao' => '㒛㚋㢯㪕㹦䂏䂽䄪䉆䔙䘟䳂伄凋刁刟叼吊奝屌弔弴彫扚掉殦汈琱瘹瞗碉窎窵竨簓蓧藋虭蛁訋調调貂釣鈟銱鋽鑃钓铞铫雕雿魡鮉鯛鲷鳭鵰鼦', + 'Die' => '㑙㥈㦅㦶㩸㩹㫼㬪㲲㲳㷸䏲䞇䠟䪓䫕䳀䴑叠哋喋嗲垤堞峌嵽幉恎惵戜挕揲昳曡殜氎爹牃牒瓞畳疂疉疊眣眰碟絰绖耊耋胅臷艓苵蜨蝶褋褺詄諜谍趃跌蹀迭镻鰈鲽', + 'Ding' => '㝎㣔㫀㴿䦺丁仃叮啶奵定嵿帄忊椗濎玎疔盯矴碇碠磸耵聢腚萣薡虰蝊訂订酊釘鋌錠鐤钉铤锭靪頂顁顶飣饤鼎鼑𦩘', + 'Diu' => '丟丢銩铥𠲍', + 'Dong' => '㑈㓊㖦㚵㢥㨂㼯䂢䍶䞒䰤䵔东侗倲働冬冻凍动動咚垌埬墥姛娻嬞岽峒崠崬徚恫懂戙挏昸東栋棟氡氭洞涷湩硐笗箽絧胨胴腖苳菄董蕫蝀諌迵霘駧鮗鯟鶇鶫鸫鼕', + 'Dou' => '㛒㞳㢄㨮㪷䄈䇺䕆䛠䬦乧兜兠吺唗唞抖斗斣枓梪橷毭浢痘窦竇篼脰荳蔸蚪豆逗郖都酘鈄閗闘阧陡餖饾鬥鬦鬪鬬鬭', + 'Du' => '㓃㞘㱩㸿㾄䀾䈞䓯䙱䟻䢱䦠䩲䪅䫳䮷䲧凟剢匵厾嘟堵妒妬嬻帾度杜椟櫝殬殰毒涜渎渡瀆牍牘犊犢独獨琽瓄皾督睹碡秺笃篤肚芏荰蝳螙蠧蠹裻覩読讀讟读豄賭贕赌醏錖鍍鑟镀闍阇靯韇韣韥騳髑黩黷', + 'Duan' => '㟨㫁㱭䠪偳剬塅媏断斷椴段毈煅瑖短碫端簖籪緞缎耑腶葮褍躖鍛鍴锻', + 'Dui' => '㙂㟋㠚㨃㬣㳔䂙䇏䜃䨴䨺䬈䭔䯟兊兌兑垖堆塠对対對嵟怼憝憞懟濧瀩痽碓磓祋綐薱襨譈譵鐓鐜镦队陮隊頧鴭𠂤𢟋𣝉', + 'Dun' => '䃦䔻䤜䪃伅吨噸囤墩墪庉惇撉撴敦楯橔沌潡炖燉犜獤盹盾砘碷礅蜳趸踲蹲蹾躉逇遁遯鈍钝頓顿驐𥫱', + 'Duo' => '㖼㙍㙐㛆㛊㣞㥩㻔㻧䅜䐾䑨䒳䙃䙤䠤䤪䤻䩔䫂䯬䲊亸凙刴剁剟剫咄哆哚喥嚉嚲垛垜埵堕墮墯多夛夺奪奲尮崜嶞惰憜挅挆掇敓敚敠敪朵朶柁柮桗椯毲畓痥綞缍舵裰趓跢跥跺踱躱躲軃鈬鍺鐸铎陊陏飿饳鮵鵽', + 'E' => '㓵㔩㖾㗁㟧㠋㣂㦍㧖㩵㮙㷈㼂䄉䆓䋪䑥䑪䕏䖸䛖䝈䞩䣞䩹䫷䱮䳗䳘䳬俄偔僫匎卾厄吪呃呝咢咹噁噩囮垩堊堮妸妿姶娥娿婀屙屵岋峉峨峩崿廅恶悪惡愕戹扼搤搹擜枙櫮歞歺涐湂珴琧痾皒睋砈砐砨硆磀礘腭苊莪萼蕚蚅蛾蝁覨訛詻誐諤譌讍讹谔豟軛軶轭迗遌遏遻鄂鈋鈪鍔鑩锇锷閼阏阨阸頋頞頟額顎颚额餓餩饿騀魤魥鰐鰪鱷鳄鵈鵝鵞鶚鹅鹗齃齶', + 'Ei' => '誒诶', + 'En' => '䅰䬶䭓䭡奀峎恩摁煾蒽𡟯', + 'Eng' => '鞥', + 'Er' => '㒃㖇㚷㛅㢽㧫䋙䋩䌺䎟䎠䎶䏪䣵䮘二佴侕儿児兒刵厼咡唲尒尓尔峏弍弐栭栮樲毦洏洱爾珥粫而耳聏胹荋薾衈袻誀貮貳贰趰輀轜迩邇鉺铒陑隭餌饵駬髵鮞鲕鴯鸸', + 'Fa' => '㕹㘺㛲䂲䇅䣹乏伐佱傠发垡姂彂栰橃沷法浌灋珐琺疺発發瞂砝笩筏罚罰罸茷蕟藅醱鍅閥阀髪髮', + 'Fan' => '㕨㛯㠶㤆㴀㶗㸋㺕㼝㽹䀀䀟䉊䉒䊩䋣䋦䌓䐪䒦䕰䛀䡊䣲䪛䪤䫶䭵䮳仮凡凢凣勫匥反噃墦奿婏嬎嬏帆幡忛憣払旙旛杋柉梵棥樊橎氾汎泛渢滼瀪瀿烦煩燔犯璠畈番盕矾礬笲笵範籓籵緐繁繙羳翻膰舤舧范蕃薠藩蘩蠜襎訉販贩蹯軓軬轓返釩鐇鐢钒颿飜飯飰饭鱕鷭𠆩𫔍𬸪', + 'Fang' => '㑂㕫㤃㧍㯐䄱䢍䲱仿倣匚坊埅堏妨彷房放方旊昉昘枋汸淓牥瓬眆紡纺肪舫芳蚄訪访趽邡鈁錺钫防髣魴鰟鲂鴋鶭', + 'Fei' => '㔗㥱㩌㫵㵒㹃䆏䈈䉬䑔䒈䕁䕠䚨䛍䠊䤵䨽䨾䩁䰁俷剕匪厞吠啡奜妃婓婔屝废廃廢悱扉斐昲暃曊朏杮棐榧櫠沸淝渄濷狒猆疿痱癈篚緋绯翡肥肺胇胐腓芾菲萉蕜蜚蜰蟦裶誹诽費费鐨镄陫霏靅非靟飛飝飞餥馡騑騛鯡鲱鼣𢳁𤷂𩹉𬴂', + 'Fen' => '㤋㥹㬟㱵㷊㸮㿎䩿䴅份偾僨兝兺分吩哛坟墳奋奮妢岎帉幩弅忿愤憤昐朆朌枌梤棻棼橨氛汾濆瀵炃焚燌燓秎竕粉粪糞紛纷羒羵翂肦膹芬蒶蕡蚠蚡衯訜豮豶躮轒酚鈖鐼隫雰餴饙馚馩魵鱝鲼黂黺鼖鼢', + 'Feng' => '㐽㒥㛔㜂㠦㡝㦀㵯䀱䏎䒠䙜䟪䩼丰仹俸偑僼冯凤凨凬凮唪堸夆奉妦寷封峯峰崶捀摓枫桻楓檒沣沨浲湗溄漨灃烽焨煈犎猦琒甮疯瘋盽砜碸篈綘縫缝艂葑蘴蜂蠭覂諷讽豐賵赗逢鄷酆鋒鎽鏠锋闏霻靊風飌风馮鳯鳳鴌麷', + 'Fiao' => '覅', + 'Fo' => '仏坲梻', + 'Fou' => '否妚殕紑缶缹缻裦雬鴀', + 'Fu' => '㓡㕊㕮㙏㚆㚕㜑㟊㠅㤔㤱㩤㪄㫙㬼㭪㲗㳇㷆㽬㾈䂤䃿䄮䋨䋹䌗䌿䍖䎔䑧䒄䒇䓏䓵䔰䕎䗄䘀䘠䝾䞜䞞䞯䞸䟔䟮䠵䡍䦣䨗䨱䩉䫍䫝䭮䭸䭻䮛䱐䳕䴸䵾乀乶付伏伕佛俌俘俛俯偩傅冨冹凫刜副匐呋咈咐哹嘸坿垘垺复夫妇妋姇娐婦媍嬔孚孵富尃岪峊巿幅幞府弗弣彿復怤怫懯扶抚拂拊捬撨撫敷斧旉服枎柎柫栿桴棴椨椱榑氟泭洑浮涪滏澓炥烰焤父玞玸琈甫甶畉畐痡癁盙砆砩祓祔福禣秿稃稪竎符笰筟箙簠粰糐紨紱紼絥綍綒緮縛绂绋缚罘罦翇肤胕腐腑腹膚艀艴芙芣苻茀茯荂荴莩菔萯葍蕧虙蚥蚨蚹蛗蜅蜉蝜蝠蝮衭袝袱複褔襆襥覄覆訃詂諨讣豧負賦賻负赋赙赴趺跗踾輔輹輻辅辐邞郙郛鄜酜釜釡鈇鉘鉜鍑鍢阜阝附陚韍韨頫颫馥駙驸髴鬴鮄鮒鮲鰒鲋鳆鳧鳬鳺鴔鵩鶝麩麬麱麸黻黼', + 'Ga' => '呷嘎嘠噶尕尜尬旮玍錷钆魀', + 'Gai' => '㕢㧉㮣㱾䀭䏗䐩䪱䬵丐乢侅匃匄垓姟峐忋戤摡改晐杚概槩槪溉漑瓂畡盖祴絠絯荄葢蓋該该豥賅賌赅郂鈣钙阣陔隑𬮿', + 'Gan' => '㓧㤌㶥㽏㿻䃭䇞䊻䤗䯎䲺䵟乹乾亁仠倝凎凲坩尲尴尶尷干幹忓感扞擀攼敢旰杆柑桿榦橄檊汵泔淦漧澉灨玕甘疳皯盰矸秆稈竿笴筸簳粓紺绀肝芉苷衦詌贑贛赣赶趕迀酐骭魐鰔鱤鳡鳱', + 'Gang' => '㟠㟵㧏㭎㼚㽘䚗䴚冈冮刚剛堈堽岗岡崗戅戆掆杠棡槓港焵焹牨犅疘矼筻綱纲缸罁罓罡肛釭鋼鎠钢鿍', + 'Gao' => '㚏㚖㤒㵆㾸䆁䓘勂吿告夰峼搞暠杲槀槁槔槹橰檺櫜滜皋皐睾祮祰禞稁稾稿筶篙糕縞缟羔羙膏臯菒藁藳誥诰郜鋯锆镐韟餻高髙鷎鷱鼛', + 'Ge' => '㖵㗆㠷㤎㦴㭘㵧㷴䈓䐙䔅䗘䘁䛿䧄䨣䪂䪺䫦个仡佮個割匌各呄咯哥哿嗝嗰圪塥彁愅戈戓戨挌搁搿擱敋格槅櫊歌滆滒牫牱犵獦疙硌箇纥肐胳膈臵舸茖葛虼蛒袼裓觡諽謌輵轕鎶铬镉閣閤阁隔革鞈鞷韐韚騔骼鬲鮯鴐鴚鴿鸽𥺊𦨜', + 'Gei' => '給给', + 'Gen' => '㫔㮓䫀亘亙哏揯搄根艮茛跟', + 'Geng' => '㹴㹹㾘䋁䌄䎴䢚䱍䱎䱭䱴刯哽埂堩峺庚挭暅更梗椩浭焿畊絚綆緪縆绠羮羹耕耿莄菮賡赓郠骾鯁鲠鶊鹒𬒔', + 'Gong' => '㓋㓚㔶㕬㤨㧬㫒㭟㯯㺬㼦䂬䂵䇨䍔䐵䔈䡗䢼䰸䱋䲲䳍供公共功匑匔厷唝塨宫宮工巩幊廾弓恭愩慐拱拲攻杛栱汞熕珙碽糼羾肱莻蚣觥觵貢贡躬躳輁鞏髸龏龔龚', + 'Gou' => '㗕㝅㝤㡚㨌㺃㽛䃓䑦䝭䬲佝冓勾坸垢够夠姤媾岣彀搆撀构枸構沟溝煹狗玽笱篝簼緱缑耇耈耉芶苟茩蚼袧褠覯觏訽詬诟豿購购遘鈎鉤钩雊鞲韝', + 'Gu' => '㒴㚉㧽㯏㼋㽽㾶䀇䀜䀦䀰䉉䍛䐨䐻䓢䜼䮩䵻䶜估傦僱凅古呱咕唂唃啒嘏固堌夃姑嫴孤尳崓崮愲扢故柧梏棝榖榾橭毂汩沽泒淈濲瀔牯牿痼皷皼盬瞽祻稒穀笟箍箛篐糓縎罛罟羖股脵臌苽菇菰蓇薣蛄蛊蛌蠱觚詁诂谷軱軲轂轱辜逧酤鈲鈷錮钴锢雇顧顾餶馉骨鮕鯝鲴鴣鶻鸪鹄鹘鼓鼔𢝳𦙶', + 'Gua' => '㒷㧓㶽䈑䏦䒷䫚䯄䯏冎刮剐剮劀卦叧啩坬寡挂掛栝歄煱瓜絓緺罣罫聒胍褂詿诖趏踻銽颪颳騧鴰鸹', + 'Guai' => '㧔㾩䂯䂷䊽乖叏夬怪恠拐掴摑枴柺箉𡇸𢶒𣲾', + 'Guan' => '㮡㴦䎚䏓䗆䗰䘾䙛䙮䚪䝺䤽䦎䩪䪀䲘丱倌关冠官悹悺惯慣掼摜棺樌毌泴涫潅灌爟琯瓘痯瘝癏盥矔礶祼窤筦管罆罐舘莞蒄覌観觀观貫贯躀輨遦錧鏆鑵関闗關雚館馆鰥鱞鱹鳏鳤鸛鹳', + 'Guang' => '㤮㫛侊俇僙光咣垙姯广広廣撗桄欟洸灮炗炚炛烡犷獷珖胱臦臩茪輄逛銧黆𨐈', + 'Gui' => '㔳㧪㨳㪈㰪㲹㸵䁛䃽䅅䈐䌆䍯䐴䝿䞈䞨䠩䣀䤥䲅䳏亀佹傀刽刿劊劌匦匭匱厬圭垝妫姽媯嫢嬀宄嶡巂帰庋庪廆归恑摫撌攰攱昋晷朹柜桂桧椝椢槶槻槼檜櫃櫷歸氿湀炔猤珪瑰璝瓌癐癸皈瞡瞶硅祪禬窐筀簂簋胿膭茥蓕蛫螝蟡袿襘規规觤詭诡貴贵跪軌轨邽郌閨闺陒鞼騩鬶鬹鬼鮭鱖鱥鲑鳜龜龟', + 'Gun' => '㙥㨰㯻䃂䎾䜇䵪丨惃棍滚滾璭睔睴磙緄绲蓘蔉衮袞謴輥辊鮌鯀鲧𠃌', + 'Guo' => '㕵㗻㳀㳡㶁㿆䂸䆐䙨䬎䴹呙咼啯嘓囯囶囻国圀國埚堝墎崞帼幗彉彍惈慖果椁槨淉漍濄猓瘑粿綶聝腘膕菓蔮虢蜾蝈蟈裹褁輠过過郭鈛錁鍋鐹锅餜馃馘', + 'Ha' => '哈奤蛤铪𡄟', + 'Hai' => '㜾㤥㧡㨟㰧㰩㱼㺔㾂䇋䠽䯐䱺亥咍咳嗐嗨嚡塰妎孩害氦海烸胲还還酼醢頦餀饚駭駴骇骸𠹛', + 'Han' => '㑵㒈㖤㘎㘕㘚㟏㟔㢨㤷㨔㪋㮀㲦㵄㶰㸁㺖㺝㼨䈄䍐䍑䎏䎯䏷䓍䓿䕿䗙䗣䘶䛞䣻䤴䥁䧲䨡䫲䮧䶃丆佄傼兯函凾厈含咁哻唅喊圅垾娢嫨寒屽岾崡嵅悍憨憾捍撖撼旱晗晘暵梒歛汉汗浛浫涆涵漢澏瀚焊焓熯爳猂琀甝皔睅筨罕翰肣莟菡蔊蘫虷蚶蛿蜬蜭螒譀谽豃邗邯酣釬銲鋎鋡閈闬阚雗韓韩頇頷顄顸颔馠馯駻鬫魽鶾鼾', + 'Hang' => '㤚㰠䀪䂫䘕䟘䣈䦭䲳垳夯斻杭沆珩笐筕絎绗航苀蚢貥迒頏颃魧', + 'Hao' => '㘪㙱㚪㝀㞻㠙㩝㬔㬶䒵䚽䝞䝥䧚䧫䪽䯫傐儫号哠嗥嘷噑嚆嚎壕好恏悎昊昦晧暤暭曍椃毜毫浩淏滈澔濠灏灝獆獋獔皓皜皞皡皥秏竓籇耗聕茠蒿薃薅薧號蚝蠔諕譹豪貉郝鄗鎬顥颢鰝', + 'He' => '㕡㗿㥺㪃㪉㬞㭱㮝㮫㰤㵑㷎㹇㿣㿥䃒䅂䏜䒩䕣䚂䞦䢔䫘䮤䳽䶅䶎何佫劾合呵咊和哬啝喝嗃嗬垎壑姀寉峆惒抲敆曷柇核楁欱毼河涸渮澕焃煂熆熇燺爀狢癋皬盇盉盍盒碋礉禾秴穒篕籺粭紇翮翯荷菏萂蚵螛蠚袔褐覈訶訸詥謞诃貈賀贺赫輅郃鉌鑉闔阂阖靍靎靏鞨頜颌饸魺鲄鶡鶮鶴鸖鹖鹤麧齕龁龢', + 'Hei' => '㱄嘿潶黑黒𨭆𬭶', + 'Hen' => '㯊䓳佷很恨拫狠痕詪鞎𬣳', + 'Heng' => '㔰㶇䬖䬝䯒亨哼啈堼姮恆恒悙桁横橫涥烆胻脝蘅衡鑅鴴鵆鸻𧝒', + 'Hm' => '噷', + 'Hong' => '㖓㗢㢬㬴㶹䀧䃔䆖䆪䉺䎕䞑䡌䡏䧆䨎䩑䪦䫹䫺䲨仜叿吰吽呍哄嗊嚝垬妅娂宏宖弘彋揈撔晎汯泓洪浤渱渹潂澋澒灴烘焢玒玜硔硡竑竤粠紅紘紭綋红纮翃翝耾苰荭葒葓蕻薨虹訇訌讧谹谼谾軣輷轟轰鈜鉷銾鋐鍧閎閧闀闂闳霐霟鞃鬨魟鴻鸿黉黌', + 'Hou' => '㖃㗋㤧㫗㬋㮢㸸㺅䂉䗔䙈䞀䞧䪷䫛䳧侯候厚后吼喉垕堠帿後洉犼猴瘊睺矦篌糇翭翵葔豞逅郈鄇鍭餱骺鮜鯸鱟鲎鲘齁', + 'Hu' => '㕆㗅㦆㦌㧮㧾㨭㪶㫚㯛㳷㷤㸦㺀㺉㽇㾰䁫䇘䈸䉿䊀䊺䍓䎁䓤䕶䗂䚛䞱䠒䧼䨚䨼䩐䩴䪝䬍䭅䭌䭍䰧䴣䴯乎乕乥乯互俿冱冴匢匫呼唬唿喖嗀嘑嘝嚛囫垀壶壷壺婟媩嫭嫮寣岵帍幠弖弧忽怘怙恗惚戯戶户戸戽扈抇护搰摢斛昈昒曶枑楛楜槲槴歑汻沍沪泘浒淴湖滬滸滹瀫烀焀煳熩狐猢琥瑚瓠瓳祜笏箶簄粐糊絗綔縠胡膴芐苸萀葫蔛蔰虍虎虖虝蝴螜衚觳謼護軤轷鄠醐錿鍙鍸隺雐雽韄頀頶餬鬍魱鯱鰗鱯鳠鳸鵠鶘鶦鸌鹕鹱', + 'Hua' => '㓰㕦㕲㕷㚌㟆㠏㦊㭉㳸䀨䇈䋀䔢䛡䱻䴳䶤划劃化华哗嘩埖夻姡婲婳嫿嬅崋搳摦撶杹桦椛槬樺滑澅猾画畫畵硴磆糀繣舙花芲華蒊蕐蘤螖觟話誮諙諣譁譮话釪釫鋘錵鏵铧驊骅鷨黊', + 'Huai' => '㜳㠢䃶咶坏壊壞徊怀懐懷槐櫰淮瀤耲蘹蘾褢褱踝', + 'Huan' => '㕕㡲㣪㪱㬇㬊㵹㶎㹕㹖㼫㿪䀓䆠䈠䍺䒛䝠䠉䥧䦡䭴䯘䴉䴋䴟唤喚喛嚾圜奂奐嬛宦寏寰峘嵈幻患愌懽换換擐攌桓梙槵欢歓歡洹浣涣渙漶澣澴烉焕煥犿狟獾环瑍環瓛痪瘓睆糫絙綄緩繯缓缳羦肒荁萈萑藧讙豢豲貆貛轘逭郇酄鉮鍰鐶锾镮闤阛雈驩鬟鯇鯶鰀鲩鴅鵍鹮𤩽𬘫', + 'Huang' => '㞷㠵㡃㤺㨪㬻㾮㿠䀮䁜䄓䅣䅿䊗䊣䌙䍿䐠䑟䞹䪄䮲䳨偟兤凰喤堭塃墴奛媓宺崲巟幌徨怳恍惶愰慌晃晄曂朚楻榥櫎湟滉潢炾煌熀熿獚瑝璜癀皇皝皩磺穔篁篊簧縨肓艎荒葟蝗蟥衁詤諻謊谎趪遑鍠鎤鐄锽隍韹餭騜鰉鱑鳇鷬黃黄𨱑', + 'Hui' => '㑰㑹㜇㞀㞧㤬㥣㧑㨤㨹㩓㩨㫎㬩㱱㷄㷇㷐㹆㻅㾯䂕䃣䅏䌇䏨䕇䖶䛛䛼䜋䜐䝅䤧䧥䩈䫭会佪僡儶匯卉咴哕喙嘒噅噕噦嚖囘回囬圚婎媈嬒孈寭屶屷幑廻廽彗彙彚徻徽恚恛恢恵悔惠慧憓懳拻挥揮撝晖晦暉暳會楎槥橞檅檓櫘殨毀毁毇汇泋洃洄浍湏滙潓澮濊瀈灰灳烠烣烩煇燬燴獩珲璤璯痐瘣睳瞺禈秽穢篲絵繢繪绘缋翙翚翬翽芔茴荟蔧蕙薈薉藱蘳虺蚘蛔蛕蜖蟪袆褘詯詼誨諱譓譭譿讳诙诲豗賄贿輝辉迴逥鏸鐬闠阓隓隳靧頮顪颒餯鮰鰴麾', + 'Hun' => '㑮㖧㥵㨡㮯䅙䅱䊐䎜䚠䛰䡣䧰䫟䮝䰟䴷俒倱圂堚婚忶惛慁掍昏昬梡棔殙浑涽混渾溷焝琿睧睯繉荤葷觨諢诨轋閽阍餛馄魂鼲𦞢', + 'Huo' => '㓉㖪㗲㘞㦎㦜㦯㨯㩇㯉㸌㺢䁨䂄䄀䄆䄑䉟䐸䣶䦝䨥䬉䰥䱛伙佸俰剨劐吙咟嚄嚯嚿夥奯惑或捇掝攉旤曤楇檴沎活湱漷濩瀖火獲癨眓矆矐砉祸禍秮秳穫耠耯臛艧获蒦藿蠖謋豁貨货邩鈥鍃鑊钬锪镬閄霍靃騞', + 'Ji' => '㑧㒫㔕㗊㗱㘍㙨㙫㚡㚻㛷㞃㞆㞛㞦㠍㠎㠱㡭㡮㤂㥍㥛㦘㦸㧀㨈㫷㭲㮨㮷㰟㲅㲺㳵㴉㴕㸄㹄㻑㻷㽺㾊㾵䀈䁒䁶䂑䇫䋟䍤䐀䐕䐚䓽䕤䗁䗗䚐䛋䛴䜞䝸䞘䟇䟌䠏䢋䢳䣢䤒䦇䨖䩯䮺䰏䲯䳭䶓䶩丌丮乩亟亼亽伋伎佶偈偮僟兾冀几击刉刏剂剞剤劑勣卙即卽及叝叽吉咭哜唧喞嗘嘰嚌圾坖垍基塈塉墼妀妓姞姫姬嫉季寂寄屐岌峜嵆嵇嵴嶯己幾庴廭彐彑彶徛忌忣急悸惎愱懻戟戢技挤掎揤撃撠擊擠敧旡既旣暨暩曁朞机极枅梞棘楫極槉槣樭機橶檕檝檵櫅殛毄汲泲洎济済湒漃漈潗激濈濟瀱焏犄犱狤玑璣畸畿疾痵瘠癠癪皀皍矶磯祭禝禨积稘稩稷稽穄穊積穖穧笄笈筓箕箿簊籍紀紒級継緝績繋繼级纪继绩缉罽羁羇羈耤耭肌脊膌臮艥芨芰茍茤荠葪蒺蓟蔇蕀蕺薊薺藉蘎蘮蘻虀虮螏蟣裚襀襋覉覊覬觊觙觭計記誋諅譏譤计讥记诘谻賫賷赍趌跡跻跽踖蹐蹟躋躤躸輯轚辑迹郆鄿銈銡錤鍓鏶鐖鑇鑙际際隮集雞雦雧霁霵霽鞿韲飢饑饥驥骥髻鬾魕魢鯚鰶鰿鱀鱭鱾鲚鲫鳮鵋鶏鶺鷄鷑鸄鸡鹡麂齌齎齏齑', + 'Jia' => '㕅㚙㪴㮖㹢㿓䀫䂟䑝䕒䕛䛟䩡䴥乫价伽佳假傢價加叚唊嘉圿埉夹夾婽嫁家岬幏徦忦恝戛戞扴抸拁斚斝架枷梜椵榎榢槚檟毠泇浃浹犌猳玾珈甲痂瘕稼笳糘耞胛腵茄荚莢葭蛱蛺袈袷裌豭貑賈贾跏跲迦郏郟鉀鉫鉿鋏鎵钾铗镓頬頰颊餄駕驾鴶鵊麚𡊠𥞵𬂩', + 'Jian' => '㓺㔋㔓㡨㣤㦰㨴㨵㭴㯺㰄㳨㵎㶕䄯䅐䇟䉍䌑䌠䓸䔐䘋䚊䟅䟰䤔䥜䧖䬻䭈䭠䮿䯡䵡䵤䶠䶢䶬件俭俴倹健僭儉兼冿减剑剣剪剱劍劎劒劔劗囏囝坚堅堿墹奸姦姧寋尖幵建弿彅徤惤戋戔戩戬拣挸捡揀揃搛撿擶旔暕枧柬栫梘检検椷椾楗榗樫橺檢櫼歼殱殲毽洊涧渐減湔湕溅漸澗濺瀐瀳瀸瀽煎熞熸牋牮犍猏玪珔瑊瑐监監睑睷瞷瞼硷碊碱磵礀礆礛笕笺筧简箋箭篯簡籛糋絸緘縑繝繭缄缣翦肩腱臶舰艦艰艱茧荐菅菺葌葥蒹蔪蕑蕳薦藆虃螹蠒袸裥襇襉襺見覵覸见詃諓諫謇謭譼譾谏谫豜豣賎賤贱趝趼践踐踺蹇轞釼鉴鋻鍳鍵鏩鐗鐧鐱鑑鑒鑬鑯鑳锏键間间鞬鞯韀韉餞餰饯馢鬋鰎鰹鲣鳒鳽鵳鶼鹣鹸鹻鹼麉', + 'Jiang' => '㢡㯍㹔䁰䉃䋌䒂䗵䜫䞪䥒傋僵勥匞匠壃夅奖奨奬姜将將嵹弜弶彊摪摾杢桨槳橿櫤殭江洚浆滰漿犟獎畕畺疅疆礓糡糨絳繮绛缰翞耩膙茳葁蒋蔣薑螀螿袶講謽讲豇酱醤醬降韁顜鱂鳉', + 'Jiao' => '㠐㩰㬭㭂㰾㲬㳅㶀㽱㽲䀊䂃䌭䍊䘨䚩䢒䥞䴔䶰交佼侥僥僬儌剿劋叫呌嘂嘄嘦噍噭姣娇嬌嬓孂峤峧嶕嶠嶣徺徼恔憍憿挍挢捁搅摷撟撹攪敎教敫敽敿斠晈暞曒椒櫵浇湫湬滘漖潐澆灚烄焦煍燋燞狡獥珓璬皎皦皭矫矯礁穚窌窖笅簥絞繳纐绞缴胶脚腳膠膲臫艽芁茭茮蕉藠虠蛟蟜蟭角訆譑譥賋趭跤踋較轇轎轿较郊酵醮釂鉸鐎铰隦餃饺驕骄鮫鱎鲛鵁鵤鷦鷮鹪', + 'Jie' => '㑘㓗㔚㘶㛃㝏㞯㠹㦢㨗㨩㫸㮞㮮㸅㼪㾏㿍䀷䀹䂝䂶䃈䅥䇒䌖䕙䕸䗻䛺䣠䥛䦈䯰䰺䱄䲙䲸丯介借倢偼傑刦刧刼劫劼卩卪吤喈喼嗟堦堺姐婕媎媘媫嫅孑尐屆届岊岕崨嵥嶻巀幯庎徣悈戒截拮捷接掲掶揭擑擮昅杰桀桝椄楐楬楶榤檞櫭毑洁湝滐潔煯犗玠琾界畍疌疖疥痎癤皆睫砎碣礍秸稭竭節結絜结羯脻节芥莭菨蓵蚧蛶蜐蝍蝔蠘蠞蠽街衱衸袺褯解觧訐詰誡誱謯讦诫踕迼鉣鍻鎅阶階鞂鞊颉飷骱魝魪鮚鲒鶛', + 'Jin' => '㝻㦗㧆㨷㬐㬜㯲㯸㱈㴆㶦㶳㹏㻱䀆䃡䆮䈥䈽䋮䌍䌝䑤䒺䗯䘳䝲䤐䤺䥆䫴䭙䶖仅今伒侭僅僸儘兓凚劤劲勁卺厪唫噤嚍埐堇堻墐壗妗嫤嬧寖尽嶜巹巾廑惍搢斤晉晋枃槿歏殣津浕浸溍漌濅濜烬煡燼珒琎琻瑨瑾璡璶盡矜矝砛祲禁筋紟紧緊縉缙荕荩菫蓳藎衿襟覲觐觔謹谨賮贐赆近进進金釒釿錦钅锦靳饉馑鹶黅齽', + 'Jing' => '㘫㢣㣏㬌䔔䜘䝼䪫䴖䵞丼井京亰俓倞傹儆兢净凈刭剄坓坕坙境妌婙婛婧宑巠幜弪弳径徑惊憬憼敬旌旍景晶暻曔桱梷橸汫汬泾浄涇淨瀞燝猄獍璄璟璥痉痙睛秔稉穽竞竟竧竫競竸粳精経經经聙肼胫脛腈茎荆荊莖菁葏蟼誩警踁迳逕鏡镜阱靓靖静靚靜頚頸颈驚鯨鲸鵛鶁鶄麖麠鼱𠲮𠷐', + 'Jiong' => '㓏㢠㤯㯋㷗㷡䌹䢛侰僒冂冋冏囧坰埛扃泂浻澃炅炯烱煚煛熲燛窘絅綗蘏蘔褧迥逈颎駉駫𣔲𬳶', + 'Jiu' => '㝌㠇㡱㩆㲃㸨㺩㺵䅢䆒䆶䊆䊘䛮䡂䬨䳎丩久乆九乣倃僦勼匓匛匶厩咎啾奺就廄廏廐慦捄揂揪揫摎救旧朻杦柩柾桕樛欍殧汣灸牞玖疚究糺糾紤纠臼舅舊舏萛赳酒镹阄韭韮鬏鬮鯦鳩鷲鸠鹫麔齨', + 'Ju' => '㖩㘌㘲㜘㞐㞫㠪㡹㥌㨿㩀㩴㪺㬬㮂㹼㽤䀠䃊䄔䅓䅕䈮䋰䎤䏱䕮䗇䛯䜯䝻䡞䢸䢹䣰䤎䪕䪶䰬䱟䱡䳔䴗䵕䶙举乬侷俱倨倶僪具冣凥剧劇勮匊句咀啹埧埾壉姖娵婅婮寠局居屦屨岠崌巈巨巪弆怇怐怚惧愳懅懼抅拒拘拠挙挶据掬據擧昛桔梮椇椈椐榉榘橘檋櫸欅歫毩毱沮泃泦洰涺淗湨澽炬烥焗爠犋犑狊狙琚疽痀眗矩砠秬窭窶筥簴粔粷罝耟聚聥腒舉艍苣苴莒菊菹蒟蘜虡蚷蜛袓裾襷詎諊讵豦貗趄趜跔跙距跼踘踞踽蹫躆躹輂遽邭郹醵鉅鋦鋸鐻钜锔锯閰陱雎鞠鞫颶飓駏駒駶驧驹鮈鮔鴡鵙鵴鶋鶪鼰鼳齟龃', + 'Juan' => '㢧㢾㪻㯞㷷䄅䅌䌸䖭䚈䡓䣺䳪倦劵勌勬卷呟埍奆姢娟巻帣慻捐捲桊涓淃焆狷獧瓹眷睊睠絭絹縳绢罥羂脧臇菤蔨蠲裐鄄錈鎸鐫锩镌隽雋飬餋鵑鹃𠔉', + 'Jue' => '㔃㔢㟲㤜㩱㭈㭾㰐㲄㵐㷾㸕㹟㻕䀗䁷䇶䏐䏣䐘䖼䘿䙠䝌䞵䞷䠇䡈䣤䦆䦼亅倔傕决刔劂勪匷厥噘噱嚼孒孓屩屫崛嶥弡彏憠憰戄抉挗捔掘撅撧攫斍桷橛橜欔欮殌氒決泬灍焳熦爑爝爴爵獗玃玦玨珏瑴疦瘚矍矡砄絕絶绝臄芵蕝蕨虳蚗蟨蟩覐覚覺觉觖觼訣譎诀谲貜赽趉趹蹶蹷蹻躩逫鈌鐍鐝钁镢駃鴂鴃鶌鷢龣', + 'Jun' => '㑺㒞㕙㖥㚬㝦㴫㻒㽙䇹䐃䕑䜭䝍俊儁军君呁均埈姰寯峻懏捃攈攟晙桾棞汮浚濬焌燇珺畯皲皸皹碅竣箘箟莙菌蚐蜠袀覠軍郡鈞銁銞鍕钧陖餕馂駿骏鮶鲪鵔鵕鵘麇麏麕', + 'Ka' => '䘔佧卡咔咖喀垰擖胩衉裃鉲', + 'Kai' => '㚊㪡䁗䒓䡷䤤凯凱剀剴勓嘅垲塏奒嵦开忾恺愒愷愾慨揩暟楷欬炌炏烗蒈輆鍇鎎鎧鐦铠锎锴開闓闿颽', + 'Kan' => '㘛㙳䀍䖔䘓䳚侃偘冚刊勘坎埳堪塪墈崁嵁惂戡栞槛檻欿歁看瞰矙砍磡竷莰衎輡轗闞顑龕龛', + 'Kang' => '㝩㢜㱂㼹䆲䗧䡉亢伉匟囥嫝嵻康忼慷扛抗摃槺漮炕犺砊穅粇糠躿邟鈧鏮钪閌闶鱇𡐓𩾌', + 'Kao' => '㸆䎋䐧䯌䯪丂尻拷攷栲洘烤犒考銬铐靠髛鮳鯌鲓', + 'Ke' => '㕉㕎㝓㞹㤩㪙㪼㵣㸯䆟䈖䌀䐦䙐䶗克刻剋勀勊匼可嗑坷堁壳娔客尅岢嵑嵙嶱恪愙揢搕敤柯棵榼樖殼氪渇渴溘炣牁犐珂疴瞌砢碦磕礊礚科稞窠緙缂翗胢艐苛萪薖蝌課课趷軻轲醘鈳錒钶锞顆颏颗騍骒髁', + 'Ken' => '㸧啃垦墾恳懇掯肎肯肻裉褃豤錹齦龈', + 'Keng' => '㧶㰢䃘䡩䡰劥吭坑妔挳摼牼硁硜硻誙銵鍞鏗铿阬𥉸', + 'Kong' => '㚚㤟㲁㸜䅝倥埪孔崆恐悾控涳硿空箜躻錓鞚鵼𥥅', + 'Kou' => '㓂㰯䁱䍍䳹冦剾劶口叩宼寇彄扣抠摳敂滱眍瞉瞘窛筘簆芤蔲蔻釦鷇𢂁𫸩', + 'Ku' => '㗄㠸㩿㪂㱠㵠䂗䇢䉐䔯䧊䯇䵈俈刳哭喾嚳圐堀崫库庫廤扝枯桍焅狜瘔矻秙窟絝绔苦袴裤褲趶跍郀酷骷鮬𠺟𥞴', + 'Kua' => '㐄㛻㡁䓙䠸䦚䯞侉咵垮夸姱挎胯舿誇跨銙骻', + 'Kuai' => '㔞㙕㟴㧟㱮䈛䓒䭝䯤侩儈凷哙噲圦块塊墤巜廥快擓旝狯獪筷糩脍膾蒯郐鄶鱠鲙𥢶', + 'Kuan' => '㯘䕀䥗䲌宽寛寬欵款歀窽窾臗鑧髋髖', + 'Kuang' => '㑌㾠䊯䒰䖱䯑䵃儣况劻匡匩卝哐圹壙夼岲忹恇懬懭抂旷昿曠框況洭爌狂狅眖眶矌矿砿硄礦穬筐筺絋絖纊纩誆誑诓诳貺贶軖軠軦軭邝邼鄺鉱鋛鑛鵟黋', + 'Kui' => '㒑㕟㙓㙺㚍㨒䕚䕫䖯䙆䙌䙡䟸䠑䤆䧶䫥䯓䯣䰎䳫亏刲匮喟喹嘳夔奎媿嬇尯岿巋巙悝愦愧憒戣揆晆暌楏楑樻櫆欳溃潰煃犪盔睽瞆窥窺篑簣籄聧聩聭聵腃葵蒉蕢藈蘬蘷虁虧蝰謉跬蹞躨逵鄈鍨鍷鐀鑎闚隗頄頍頯顝餽饋馈馗騤骙魁𫠆', + 'Kun' => '㡓㩲㫻㱎䐊䖵䠅䪲困坤堃堒壸壼婫尡崐崑悃捆昆晜梱涃潉焜熴猑琨瑻睏硱祵稇稛綑菎蜫裈裍裩褌貇醌錕锟閫閸阃騉髠髡髨鯤鲲鵾鶤鹍𠚯', + 'Kuo' => '㗥㾧䟯䦢䯺廓懖扩拡括挄擴桰濶筈萿葀蛞闊阔霩鞟鞹韕頢髺鬠', + 'La' => '㕇㡴㻋㻝䂰䃳䏀䓥䗶䱨䱫䶛剌啦喇嚹垃拉揦揧搚攋旯柆楋溂爉瓎瘌砬磖翋腊臈臘菈藞蜡蝋蝲蠟辢辣邋鑞镴鞡鬎鯻', + 'Lai' => '㚓㥎㸊䂾䄤䅘䋱䓶䚅䠭䧒䲚來俫倈唻婡崃崍庲徕徠来梾棶櫴涞淶濑瀨瀬猍琜癞癩睐睞筙箂籁籟莱萊藾襰賚賴赉赖逨郲錸铼頼顂騋鯠鵣鶆麳', + 'Lan' => '㑣㘓㛦㜮㞩㦨㨫㩜㰖㱫㳕䃹䆾䌫䍀䑌䦨䪍䰐儖兰厱嚂囒囕壈婪嬾孄孏岚嵐幱惏懒懢懶拦揽擥攔攬斓斕栏榄欄欖欗浨滥漤澜濫瀾灆灠灡烂燗燣燷爁爛爤爦璼瓓礷篮籃籣糷繿纜缆罱葻蓝藍蘭褴襕襤襴襽覧覽览譋讕谰躝醂鑭钄镧闌阑韊顲𠼖𡓔𢒞𥦝𨷻𬒗', + 'Lang' => '㓪㙟㝗㟍㢃㫰㮾㱢㾿䆡䍚䕞䡙䯖䱶勆唥啷埌塱嫏崀廊斏朖朗朤桹榔樃欴浪烺狼琅瑯硠稂筤艆莨蒗蓈蓢蜋螂誏躴郎郒郞鋃鎯锒閬阆駺𠺘𠻴𦵧𧚅𩷕', + 'Lao' => '㗦㞠㟉㟹㧯㨓㺐䃕䇭䕩䜎䝁䝤䲏䳓䵏佬僗劳労勞咾哰唠嗠嘮姥嫪崂嶗恅憥憦捞撈朥栳橑橯浶涝潦澇烙牢狫珯痨癆硓磱窂簩粩老耂耢耮荖蛯蟧躼軂轑酪醪銠鐒铑铹顟髝鮱', + 'Le' => '㔹㖀㦡乐了仂叻忇扐楽樂氻泐玏砳竻簕肋艻阞韷餎饹鰳鳓𡃖', + 'Lei' => '㑍㒍㒦㔣㙼㲕㴃㵢㵽㶟㹎㼍㿔䉂䉪䍣䐯䒹䛶䢮䣂䣦䨓䮑䴎傫儡儽勒厽嘞垒塁壘壨嫘擂攂樏檑櫐櫑欙泪洡涙淚灅瓃畾癗矋磊磥礌礧礨禷类累絫縲纇纍纝缧罍羸耒腂蔂蕌蕾藟蘱蘲蘽虆蠝誄讄诔轠酹銇錑鐳鑘鑸镭雷靁頛頪類颣鱩鸓鼺𠱤𡚗𥅦𥑶𧒽', + 'Leng' => '㘄䉄䬋䮚倰冷堎塄崚愣棱楞睖碐稜薐踜輘', + 'Li' => '㑦㒧㒿㓯㔏㕸㗚㘑㛤㟳㠟㠣㡂㤡㤦㦒㧰㬏㮚㯤㰀㰚㱹㴝㸚㹈㺡㻎㻺㼖㽁㽝㾐㾖㿛㿨䃯䄜䅄䅻䇐䉫䊍䊪䋥䍠䍥䍦䍽䓞䔁䔆䔉䔣䔧䕻䖥䖽䖿䗍䘈䙰䚕䟏䟐䡃䣓䣫䤙䤚䥶䧉䬅䬆䮋䮥䰛䰜䱘䲞䴡䴻䵓䵩䶘丽例俐俚俪傈儮儷兣凓刕利剓剺劙力励勵历厉厘厤厯厲吏呖哩唎唳喱嚟嚦囄囇坜塛壢娌娳婯嫠孋孷屴岦峛峢峲巁廲悡悧悷慄戾搮攊攦攭斄暦曆曞朸李杝枥栃栎栗栛梨梩梸棃棙樆檪櫔櫟櫪欐欚歴歷沥沴浬涖溧漓澧濿瀝灕爄爏犁犂犡狸猁珕理琍瑮璃瓅瓈瓑瓥疠疬痢癘癧皪盠盭睝砅砺砾磿礪礫礰礼禮禲离秝穲立竰笠筣篥篱籬粒粝粴糎糲綟縭纚缡罹脷艃苈苙茘荔荲莅莉菞蒚蒞蓠蔾藜藶蘺蚸蛎蛠蜊蜧蝷蟍蟸蠇蠡蠣蠫裏裡褵觻詈謧讈豊貍赲跞躒轢轣轹逦邌邐郦酈醨醴里釐鉝鋫鋰錅鎘鏫鑗锂隶隷隸離雳靂靋驪骊鬁鯉鯏鯬鱧鱱鱳鱺鲡鲤鳢鳨鴗鵹鷅鸝鹂麗麜黎黧', + 'Lia' => '俩倆', + 'Lian' => '㜃㜕㜻㝺㟀㡘㢘㥕㦁㪘㪝㯬㰈㰸㱨㶌㶑㺦㼑㼓䁠䃛䆂䌞䏈䙺䥥䨬䭑亷僆劆匲匳嗹噒堜奁奩媡嫾嬚帘廉怜恋慩憐戀摙敛斂梿楝槤櫣殓殮浰涟湅溓漣潋澰濂濓瀲炼煉熑燫琏瑓璉磏簾籢籨練縺纞练羷翴联聨聫聮聯脸臁臉莲萰蓮蔹薕蘝蘞螊蠊裢裣褳襝覝謰蹥连連鄻錬鍊鎌鏈鐮链镰鬑鰊鰱鲢', + 'Liang' => '㒳㔝㹁㾗䀶䁁䓣䝶䠃䣼䩫䭪両两亮俍兩凉哴唡啢喨墚悢掚晾梁椋樑涼湸煷簗粮粱糧綡緉脼良蜽裲諒谅踉輌輛輬辆辌量鍄魉魎𫟅𬜯', + 'Liao' => '㙩㝋㡻㵳㶫䄦䉼䎆䑠䒿䜍䜮䢧䨅䩍僚叾嘹嫽寥寮尞尥尦屪嵺嶚嶛廖廫憀憭撂撩敹料暸曢漻炓燎爎爒獠璙疗療瞭窷竂簝繚缭聊膋膫蓼藔蟟豂賿蹘蹽辽遼鄝釕鐐钌镣镽飉髎鷯鹩', + 'Lie' => '㤠㧜㬯㭞㭩㯿㲱㸹㼲㽟䁽䅀䉭䋑䜲䝓䟩䟹䪉䴕儠冽列劣劽咧哷埒埓姴巤挒挘捩擸栵毟洌浖烈烮煭犣猎猟獵睙聗脟茢蛚裂趔躐迾颲鬛鬣鮤鱲鴷', + 'Lin' => '㐭㔂㖁㝝㨆㷠䉮䕲䗲䚏䚬䢯䫐䫰䮼临亃僯冧凛凜厸吝啉壣崊嶙廩廪恡悋懍懔拎撛斴晽暽林橉檁檩淋潾澟瀶焛燐獜琳璘甐疄痳癛癝瞵碄磷箖粦粼繗翷膦臨菻蔺藺賃赁蹸躏躙躪轔轥辚遴邻鄰鏻閵隣霖驎鱗鳞麐麟𬭸𬴊', + 'Ling' => '㖫㡵㥄㦭㪮㬡㯪㱥㲆㸳㻏㾉䄥䈊䉁䉖䉹䌢䍅䔖䕘䖅䙥䚖䠲䡼䡿䧙䨩䯍䰱䴇䴒䴫令伶凌刢另呤囹坽夌姈婈孁岭岺嶺彾掕昤朎柃棂櫺欞泠淩澪瀮灵炩燯爧狑玲琌瓴皊砱祾秢竛笭紷綾绫羚翎聆舲苓菱蓤蔆蕶蘦蛉衑袊裬詅跉軨酃醽鈴錂铃閝阾陵零霊霗霛霝靈領领駖魿鯪鲮鴒鸰鹷麢齡齢龄龗', + 'Liu' => '㐬㙀㧕㶯㽌㽞䄂䉧䗜䚧䝀䬟䰘䱖䱞䶉六刘劉嚠塯媹嬼嵧廇懰旈旒柳栁桞桺榴橊橮沠流浏溜澑瀏熘熮珋琉瑠瑬璢畂畄留畱疁瘤癅硫磂磟綹绺罶羀翏蒥蓅藰蟉裗蹓遛鉚鋶鎏鎦鏐鐂锍镏镠雡霤飀飂飅飗餾馏駠駵騮驑骝鬸鰡鶹鷚鹠鹨麍𠺕𨢇', + 'Lo' => '囖', + 'Long' => '㑝㙙㚅㛞㝫㟖㡣㢅㦕㰍㳥㴳䃧䆍䏊䙪䡁䥢䪊䮾儱咙哢嚨垄垅壟壠屸嶐巃巄徿拢攏昽曨朧栊梇槞櫳泷湰滝漋瀧爖珑瓏癃眬矓砻礱礲窿竉竜笼篢篭籠聋聾胧茏蕯蘢蠪蠬襱豅贚躘鏧鑨陇隆隴霳靇驡鸗龍龒龓龙', + 'Lou' => '㔷㟺㡞㥪㪹㲎㺏䁖䄛䅹䝏䣚䫫䮫䱾偻僂剅喽嘍塿娄婁屚嵝嶁廔慺搂摟楼樓溇漊漏熡甊瘘瘺瘻瞜篓簍耧耬艛蒌蔞蝼螻謱軁遱鏤镂陋鞻髅髏', + 'Lu' => '㓐㔧㔪㖨㛎㛬㜙㟤㠠㠥㢚㢳㦇㪐㪖㪭㫽㭔㭚㯝㯟㯭㱺㲶㻲㼾㾔㿖䃙䌒䍡䎑䎼䐂䔞䕡䘵䚄䟿䡎䡜䥨䩮䮉䰕䱚䲐䴪侓侣侶僇儢剹勎勠勴卢卤吕呂噜嚕嚧圥坴垆垏塶塷壚娽寽屡屢履峍嵂庐廘廬彔录律慮戮挔捋捛掳摝撸擄擼攎旅曥枦栌梠椂榈樐樚橹櫓櫖櫚櫨氀氇氌氯泸淕淥渌滤滷漉潞澛濾瀂瀘炉焒熝爈爐獹率玈琭璐璷瓐甪盝盧睩矑硉硵碌磠祣祿禄稆稑穋穞穭箓箻簏簬簵簶籙籚粶絽綠緑縷繂纑绿缕罏胪膂膐膔膟膢臚舮舻艣艪艫芦菉葎蓾蔍蕗藘蘆虂虏虑虜螰蠦褛褸觮謢賂赂趢路踛蹗轆轤轳辂辘逯郘醁鈩鋁錄録錴鏀鏕鏴鐪鑢鑥鑪铝镥閭闾陆陸露顱颅馿騄騼驢驴髗魯魲鯥鱸鲁鲈鵦鵱鷜鷺鸕鸬鹭鹵鹿麓黸', + 'Luan' => '㝈㡩㱍䖂䜌乱亂卵圝圞奱娈孌孪孿峦巒挛攣曫栾欒滦灓灤癴癵羉脔臠虊釠銮鑾鵉鸞鸾', + 'Lue' => '㑼㔀㗉㨼䂮䌎䛚䤣圙掠擽略畧稤鋝鋢锊', + 'Lun' => '㖮㷍䈁䑳仑伦侖倫囵圇埨婨崘崙惀抡掄棆沦淪溣碖磮稐綸纶耣腀菕蜦論论踚輪轮錀陯鯩𫭢𬬭', + 'Luo' => '㑩㒩㓢㞅㦬㩡㪾㰁㱻㴖㼈㽋㿚䀩䇔䈷䉓䊨䌱䌴䎊䯁倮儸剆啰囉峈摞攞曪椤欏泺洛洜漯濼犖猡玀珞瘰癳硦笿箩籮絡纙络罖罗羅脶腡臝荦萝落蓏蘿螺蠃裸覙覶覼躶逻邏鉻鏍鑼锣镙雒頱饠駱騾驘骆骡鮥鴼鵅鸁', + 'M' => '呣', + 'Ma' => '㐷㑻㜫㦄㨸㾺䗫䣕䣖䧞䯦䳸亇傌吗唛嗎嘛嘜妈媽嫲嬤嬷孖杩榪溤犘犸獁玛瑪痲睰码碼礣祃禡罵蔴蚂螞蟆蟇遤鎷閁馬駡马骂鬕鰢鷌麻', + 'Mai' => '㜥㦟䁲䘑䚑䜕䨪䨫䮮买佅劢勱卖嘪埋売脈脉荬蕒薶衇買賣迈邁霡霢霾鷶麥麦鿏', + 'Man' => '㒼㗈㙢㛧㡢㬅㵘䅼䊡䐽䒥䕕䛲䜱䝡䝢䟂䡬䯶䰋僈墁姏嫚屘幔悗慢慲摱曼槾樠満满滿漫澷熳獌睌瞒瞞矕縵缦蔄蔓蘰蛮螨蟎蠻襔謾谩蹒鄤鏋鏝镘鞔顢颟饅馒鬗鬘鰻鳗', + 'Mang' => '㝑㟌㟐㟿㡛㤶㬒㻊䁳䅒䈍䒎䓼䖟䵨吂哤壾娏尨庬忙恾杗杧氓汒浝漭牤牻狵痝盲硥硭笀芒茫茻莽莾蛖蟒蠎邙釯鋩铓駹', + 'Mao' => '㒵㒻㚹㝟㡌㧇㧌㪞㫯㮘㲠㴘㺺㿞䀤䅦䋃䓮䡚䫉䭷乮兞冃冇冐冒卯堥夘媢峁帽愗懋戼旄昴暓枆柕楙毛毷氂泖渵牦犛猫瑁皃眊瞀矛笷罞耄芼茂茅茆萺蓩蝐蝥蟊袤覒貌貓貿贸軞鄚鄮酕錨铆锚髦髳鶜', + 'Me' => '么嚒嚜濹癦麼', + 'Mei' => '㙁㭑㺳䀛䆀䉋䊈䍙䓺䜸䤂䰨䰪䵢凂呅坆堳塺妹娒媄媒媚媺嬍寐嵄嵋徾抺挴攗旀昧枚栂梅楣楳槑毎每沒没沬浼渼湄湈煝煤燘猸玫珻瑂痗眉眛睂睸矀祙禖穈篃美脄脢腜苺莓葿蘪蝞袂跊躾郿酶鋂鎂鎇镁镅霉韎鬽魅鶥鹛黣黴𥞊𪃏', + 'Men' => '㥃㦖㱪㵍䊟䫒亹们們悶懑懣扪捫暪椚焖燜玧璊菛虋鍆钔門閅门闷𫞩', + 'Meng' => '㙹㜴㝱㠓㩚䀄䁅䇇䉚䏵䑃䑅䒐䓝䗈䙦䙩䟥䠢䤓䥂䥰䰒䲛䴌䴿䵆儚冡勐夢夣孟幪懜懞懵掹擝曚朦梦橗檬氋溕濛猛獴瓾甍甿盟瞢矇矒礞艋艨莔萌蒙蕄蘉虻蜢蝱蠓鄳鄸錳锰霥霿靀顭饛鯍鯭鸏鹲鼆', + 'Mi' => '㜆㜷㝥㟜㠧㣆㥝㨠㫘㳴㳽㴵㵋㸏㸓䁇䈿䉲䊳䋛䌏䌐䌕䍘䕳䕷䖑䛑䛧䣾䤉䤍䥸䭧䮭䱊䴢侎冖冞冪咪嘧塓孊宓宻密峚幂幎幦弥弭彌戂擟攠敉榓樒櫁汨沕沵泌洣淧渳滵漞濔濗瀰灖熐爢猕獼瓕眫眯瞇祕祢禰秘簚米粎糜糸縻羃羋脒芈葞蒾蔝蔤藌蘼蜜袮覓覔覛觅詸謎謐谜谧迷醚醾醿釄銤镾靡鸍麊麋麛鼏', + 'Mian' => '㒙㝃㝰㤁㨺㮌㰃㴐㻰䀎䃇䏃䛉䤄䩄䫵䰓丏偭免冕勉勔喕娩婂媔嬵宀愐杣棉檰櫋汅沔渑湎澠眄眠矈矊矏糆絻綿緜緬绵缅腼臱芇葂蝒面靣鮸麪麫麵麺黽黾', + 'Miao' => '㑤㦝䁧䖢喵妙媌嫹庙庿廟描杪淼渺玅眇瞄秒竗篎緢緲缈苗藐邈鱙鶓鹋𦳥', + 'Mie' => '㒝㩢䁾䈼䌩䘊䩏乜吀咩哶孭幭懱搣櫗滅灭烕篾蔑薎蠛衊覕鑖鱴鴓𪇴', + 'Min' => '㞶㟩㟭㥸㨉㬆䁕䂥䃉䋋䝧䟨䡑䡻䪸䲄僶冺刡勄垊姄岷崏忞怋悯惽愍慜憫抿捪敃敏敯旻旼暋民泯湣潣珉琘琝瑉痻皿盿砇碈笢笽簢緍緡缗罠苠蠠鈱錉鍲閔閩闵闽鰵鳘鴖𠊟𣷠', + 'Ming' => '㝠㟰㫥䄙䆩䊅䒌䫤䳟佲冥凕名命姳嫇慏掵明暝朙椧榠洺溟猽眀眳瞑茗蓂螟覭詺鄍酩銘铭鳴鸣', + 'Miu' => '謬谬', + 'Mo' => '㱳㶬㷬㷵㹮䁼䁿䃺䏞䒬䘃䩋䬴䭩䮬䯢䱅䳮䴲劘劰唜嗼嚤嚩嚰圽塻墨妺嫫嫼寞尛帓帞庅怽懡抹摩摸摹擵昩暯末枺模橅歾歿殁沫湐漠瀎爅獏瘼皌眜眽眿瞐瞙砞磨礳秣粖糢絈纆耱膜茉莈莫蓦藦蘑蛨蟔謨謩谟貃貊貘銆鏌镆陌靺饃饝馍驀髍魔魩魹麽麿默黙', + 'Mou' => '㭌䋷䍒䏬䗋䥐䱕侔劺哞恈某洠牟眸瞴繆缪蛑謀谋踎鉾鍪鴾麰𢃱', + 'Mu' => '㜈㟂㣎㧅㾇䀲䊾䑵䥈䱯亩仫凩募坶墓墲姆峔幕幙慔慕拇暮木朰楘母毣毪氁沐炑牡牧牳狇畆畒畝畞畮目睦砪穆縸胟艒苜莯蚞踇鉧鉬钼雮霂鞪𠺖𧿹', + 'N' => '㕶嗯𠮾', + 'Na' => '㨥㵊䇱䈫䎎䏧䖓䖧䛔䟜䪏䫱乸吶呐哪嗱妠娜拏拿挐捺笝納纳肭蒳衲袦豽貀軜那鈉鎿钠镎雫靹魶𠕄𦙜𦰡𪐀', + 'Nai' => '㜨㮈㮏㲡㴎㾍䍲䘅䯮乃倷奈奶妳嬭孻廼摨柰氖渿熋疓耏耐腉艿萘螚褦迺釢錼鼐', + 'Nan' => '㓓㫱㬮㽖䈒䊖䔜䛁䶲侽南喃囡娚婻戁抩揇暔枏柟楠湳煵男畘腩莮萳蝻諵赧遖难難', + 'Nang' => '㚂㶞䁸乪儾嚢囊囔擃攮曩欜灢蠰譨饢馕鬞齉𦣘', + 'Nao' => '㑎㛴㞪㺁䃩䛝䜀䜧䴃匘呶垴堖夒婥嫐孬峱嶩巎怓恼悩惱憹挠撓淖猱獶獿瑙硇碙碯脑脳腦臑蛲蟯詉譊鐃铙閙闹鬧', + 'Ne' => '㕯䅞䎪䭆呢抐疒眲訥讷𢗉', + 'Nei' => '㐻㨅㼏䲎內内娞氝脮腇錗餒馁鮾鯘', + 'Nen' => '㜛㯎㶧嫩嫰恁', + 'Neng' => '㲌㴰䏻能𠹌𨶙', + 'Ni' => '㞾㠜㥾㦐㩘㪒㲻㵫㹸䁥䕥䘌䘦䘽䛏䝚䦵䵑䵒伱伲你倪儗儞匿坭埿堄妮婗嫟嬺孴尼屔屰怩惄愵抳拟擬旎昵晲暱柅棿檷氼泥淣溺狔猊眤睨秜籾縌聣聻胒腝腻膩臡苨薿蚭蜺觬誽貎跜輗迡逆郳鈮铌隬霓馜鯢鲵麑齯𠱘𠸺𢘝𧏾𨺙𩺱𫐐𫠜', + 'Nian' => '㜤㞋㮟㲽䄭䄹䚓䧔䬯卄哖唸埝姩年廿念拈捻撚撵攆涊淰焾碾秊秥簐艌蔫跈蹍蹨躎輦辇辗鮎鯰鲇鲶鵇黏𨇍', + 'Niang' => '䖆娘嬢孃酿醸釀', + 'Niao' => '㒟㜵㞙㠡㭤㳮䃵䙚䦊䮍嫋嬝嬲尿樢脲茑蔦袅裊褭鳥鸟𢶑𣟊', + 'Nie' => '㖏㖕㖖㘝㘨㘿㙞㚔㜸㡪㩶㮆㴪㸎䂼䄒䇣䌜䌰䡾䯀䯅䯵䳖啮喦嗫噛嚙囁囓圼孼孽嵲嶭巕帇惗捏揑摰敜枿槷櫱涅湼痆篞籋糱糵聂聶臬臲苶菍蘖蠥讘踂踗踙蹑躡錜鎳鑈鑷钀镊镍闑陧隉顳颞齧', + 'Nin' => '㤛䋻䚾囜您拰脌', + 'Ning' => '㝕㣷㲰㿦䆨䔭䗿䭢佞侫倿儜凝咛嚀嬣宁寍寕寗寜寧拧擰柠橣檸泞澝濘狞獰甯矃聍聹苧薴鑏鬡鸋𦡲𩕳', + 'Niu' => '㖻㺲䂇䋴䏔䒜妞忸扭汼炄牛牜狃紐纽莥鈕钮靵', + 'Nong' => '㶶㺜䢉䵜侬儂农哝噥弄挊挵檂欁浓濃燶癑禯秾穠繷脓膿蕽襛農辳醲齈𪒬𬪩', + 'Nou' => '㜌㝹㳶䅶䘫䨲䰭啂槈檽獳羺耨譳鎒鐞𡝦', + 'Nu' => '㚢㵖䖡䘐䚼䶊伮傉努女奴孥弩怒恧搙朒沑砮笯籹胬衂衄釹钕駑驽', + 'Nuan' => '㬉奻暖渜煖煗餪', + 'Nue' => '䖈䖋䨋疟瘧硸虐', + 'Nun' => '黁', + 'Nuo' => '㐡㑚㔮㖠㛂㡅㰙䚥傩儺喏愞懦懧挪掿搦搻梛榒橠稬穤糑糥糯諾诺蹃逽郍锘𦀨', + 'O' => '哦喔噢筽', + 'Ou' => '㒖㼴䉱䌂䌔䙔䥲偶吘呕嘔塸怄慪櫙欧歐殴毆沤漚熰瓯甌耦腢膒蕅藕藲謳讴鏂鴎鷗鸥齵𠙶𠴰𩥋𫭟𬉼', + 'Pa' => '䔤䯲啪妑帊帕怕掱杷潖爬琶皅筢舥葩袙趴', + 'Pai' => '㭛㵺䖰䱝俳哌廹徘拍排棑派渒湃牌犤猅簰簲蒎輫鎃𠂢𣏟𥱼', + 'Pan' => '㐴㢖㽃䃲䆺䰉䰔冸判叛媻幋拚搫攀槃沜泮洀溿潘瀊炍爿牉畔畨盘盤盼眅磐磻縏聁萠蒰蟠袢襻詊跘蹣鋬鎜鑻鞶頖鵥𦙀', + 'Pang' => '㕩㥬㫄䅭䏺䒍䠙䨦乓厐厖嗙嫎庞徬旁沗滂炐耪肨胖胮膖舽螃覫逄雱霶鳑龎龐𩃎', + 'Pao' => '㘐㚿㯡㯱㲏䩝䫽䶌刨匏咆垉奅庖抛拋泡炮炰爮狍疱皰砲礟礮脬萢袍褜跑軳鞄麃麅麭', + 'Pei' => '㚰㟝㤄㧩㯁㳈㾦䊃䣙䫊伂佩俖呸培姵嶏帔怌斾旆柸毰沛浿珮肧胚蓜衃裴裵賠赔轡辔配醅锫阫陪霈馷駍', + 'Pen' => '㖹呠喯喷噴歕湓瓫盆翸葐𠽾', + 'Peng' => '㛁㠮㥊㧸㱶㼞䄘䍬䡫䥋䦕䰃䴶倗剻匉嘭堋塳弸彭怦恲憉抨挷捧掽朋梈棚椖椪槰樥淎漰澎烹熢皏砰硑硼碰磞稝竼篣篷纄膨芃莑蓬蘕蟚蟛踫軯輣錋鑝閛韸韼騯髼鬅鬔鵬鹏', + 'Pi' => '㓟㨢㨽㮰㯅㱟㳪㵨㼰㿙䏘䑀䑄䚰䚹䠘䡟䤏䤨䫌䫠䯱䰦䲹䴙䴽丕仳伓伾僻劈匹啤噼噽嚊嚭圮坯埤壀媲嫓屁岯崥庀悂憵批披抷揊擗旇朇枇毗毘毞淠潎澼炋焷狉狓琵甓疈疋疲痞癖皮睥砒磇礔礕秛秠稫篺紕纰罴羆翍耚肶脴脾腗膍芘苉蚍蚽蚾蜱螷蠯諀譬豼豾貔辟邳郫釽鈈鈚鈹鉟銔銢錃錍铍闢阰陴霹駓髬魮魾鮍鲏鴄鵧鷿鸊鼙𠜱𣓋𤷒𦘩𦨭𨈚𨑜', + 'Pian' => '㓲㛹㸤㼐㾫䏒䮁偏囨媥楄楩片犏篇翩胼腁覑諚諞谝貵賆跰蹁鍂駢騈騗騙骈骗骿魸鶣𡎚', + 'Piao' => '㬓㵱㹾㼼䏇䕯䴩僄剽勡嘌嫖彯徱慓旚殍漂犥瓢皫瞟票篻縹缥翲薸螵醥闝顠飃飄飘魒𩗏', + 'Pie' => '䥕丿嫳撆撇暼氕瞥苤鐅𠟈𬭯', + 'Pin' => '㡦㰋㺍䎙品嚬姘娦嫔嬪拼榀汖牝玭琕矉礗穦聘薲蠙貧贫頻顰频颦馪驞𬞟', + 'Ping' => '㵗㺸㻂䀻䈂䍈䓑䛣䶄乒俜凭凴呯坪塀娉屏屛岼帡帲幈平慿憑枰檘泙洴涄淜焩玶瓶甁甹砯竮箳簈缾聠胓艵苹荓萍蓱蘋蚲蛢評评軿輧郱頩鮃鲆', + 'Po' => '㗶㛘㧊㨇㩯䄸䍨䎅䞟䣪䣮䥽䨰䪖䪙䯙叵嘙坡婆尀岥岶敀昢桲櫇泊泼洦溌潑烞珀皤破砶笸粕蒪蔢謈迫鄱酦醗釙鉕鏺钋钷頗颇駊魄', + 'Pou' => '㕻㧵㰴䬌䯽䳝剖咅哣娝婄抔抙捊掊犃箁裒錇', + 'Pu' => '㒒㬥㯷㲫㹒㺪䈬䈻䑑䔕䗱䧤䮒䲕䴆仆僕匍噗圃圑圤墣巬巭扑撲擈攴攵普暜曝朴樸檏氆浦溥潽濮瀑炇烳獛璞瞨穙纀脯舖舗莆菐菩葡蒱蒲諩譜谱贌蹼酺鋪鏷鐠铺镤镨陠鯆', + 'Qi' => '㒅㖢㞓㞚㟓㟚㟢㠌㣬㥓㩻㩽㫓㬤㯦㰗㱦䀙䁈䁉䄎䄢䄫䅤䅲䉻䋯䌌䎢䏅䏌䏠䏿䐡䑴䒗䒻䓅䓫䔇䔾䗩䙄䚉䚍䞚䟄䟚䡋䡔䢀䣛䥓䧵䩓䫏䫔䭫䭬䭶䭼䰇䰴䱈䲬䳢䶒䶞七乞亓亝企俟倛僛其凄剘启呇呮咠唘唭啓啔啟嘁噐器圻埼夡奇契妻娸婍屺岂岐岓崎嵜帺弃忔忯悽愭慼慽憇憩懠戚捿掑摖攲斉斊旂旗晵暣期杞柒栔栖桤桼棄棊棋棨棲榿槭檱櫀欫欺歧气気氣汔汽沏泣淇淒湆湇漆濝炁猉玂玘琦琪璂甈畦疧盀盵矵砌碁碕碛碶磜磧磩祁祇祈祺禥竒簯簱籏粸紪綥綦綨綮綺緀緕纃绮缼罊耆肵脐臍艩芑芞芪萁萋萕葺蕲藄蘄蚑蚔蚚蛣蛴蜝蜞螧蟿蠐褀褄訖諆諬諿讫豈起跂踑蹊軝迄迉邔郪釮錡鏚锜闙霋頎颀騎騏騹骐骑鬐鬿魌鯕鰭鲯鳍鵸鶀鶈麒麡鼜齊齐', + 'Qia' => '㓞㓣㓤㡊㤉䁍䂒䨐䯊䶝冾圶峠帢恰愘拤掐殎洽硈葜跒酠鞐髂', + 'Qian' => '㐸㗔㜞㟻㦮㦿㧄㨜㩃㩮㩷㪠㯠㸫㹂䀒䁮䇂䇜䈤䈴䉦䊴䑶䕭䖍䞿䥅䪈䭤䵖䵛仟仱佥俔倩偂傔僉儙兛凵刋前千嗛圱圲堑塹墘壍奷婜媊嬱孅孯岍岒嵌嵰忴悓悭愆慊慳扦扲拑拪掔掮揵搴撁攐攑攓杄棈椠榩槏槧橬檶櫏欠欦歉歬汘汧浅淺潛潜濳灊牵牽瓩皘竏签箝箞篏篟簽籖籤粁綪縴繾缱羬肷脥膁臤芊芡茜茾蒨蔳蕁虔蚈蜸褰諐謙譴谦谴谸軡輤迁遣遷釺鈆鈐鉗鉛銭錢鎆鏲鑓钎钤钱钳铅阡雃靬韆顅騚騝騫骞鬜鬝鰜鰬鵮鹐黔黚', + 'Qiang' => '㛨㩖㳾㾤䤌䵁丬呛唴嗆嗴墏墙墻嫱嬙嶈廧強强戕戗戧抢搶斨枪椌槍樯檣溬漒炝熗牄牆猐獇玱瑲篬繈繦羌羗羟羥羫羻腔艢蔃蔷薔蘠蜣襁謒跄蹌蹡錆鎗鏘鏹锖锵镪', + 'Qiao' => '㚁㚽㝯㡑㢗㤍㴥䀉䂪䂭䃝䆻䇌䎗䩌䫞䯨䱁䲾䵲乔侨俏僑僺劁喬嘺墝墽嫶峭嵪巧帩幧悄愀憔撬撽敲桥槗樵橇橋殻毃燆犞癄瞧硗硚磽礄窍竅繑缲翘翹荍荞菬蕎藮誚譙诮谯趫趬跷踍蹺躈郻鄡鄥釥鍫鍬鐈鐰锹陗鞒鞘鞩鞽韒頝顦骹髚髜𢄹', + 'Qie' => '㓶㗫㚗㛍㛗㤲㥦㹤㼤㾀㾜䟙䤿䦧且切匧厒妾怯悏惬愜挈朅洯淁癿穕窃竊笡箧篋籡緁聺苆藒蛪踥郄鍥鐑锲鯜𨄊', + 'Qin' => '㓎㕋㘦㝲㞬㢙㤈㩒㪁㮗㾛㾣䃢䈜䔷䜷䦦䰼亲侵勤吢吣唚嗪噙坅埁媇嫀寑寝寢寴嵚嶔庈慬懃懄抋捦揿搇撳擒斳昑梫檎欽沁溱澿瀙珡琴琹瘽禽秦笉綅耹芩芹菣菦菳藽蚙螓螼蠄衾親誛赾鈙鈫鋟钦锓雂靲顉駸骎鬵鮼鳹鵭', + 'Qing' => '㩩㯳㵾㷫䋜䔛䞍䡖䨝䯧䲔倾傾儬凊剠勍卿圊埥夝寈庆庼廎情慶掅擎擏晴暒棾樈檠檾櫦殑殸氢氫氰淸清漀濪甠硘碃磬箐罄苘葝蜻請謦请輕轻郬鑋靑青靘頃顷鲭黥', + 'Qiong' => '㑋㒌㧭㮪㷀㼇䅃䆳䊄䓖䛪䠻儝卭宆惸憌桏橩焪焭煢熍琼璚瓊瓗睘瞏穷穹窮竆笻筇舼芎茕藑藭蛩蛬赹跫邛銎', + 'Qiu' => '㐀㕤㚱㛏㞗㟈㤹㥢㧨㭝㳋㷕㺫䆋䊵䎿䐐䜪䟬䟵䠓䠗䣇䤛䨂䲡丘丠俅叴唒囚坵媝崷巯巰恘扏搝梂楸殏毬求汓泅浗渞湭煪犰玌球璆皳盚秋秌穐篍糗紌絿緧肍莍萩蓲蘒虬虯蚯蛷蝤蝵蟗蠤裘觓觩訄訅賕赇趥逎逑遒邱酋醔釓釚釻銶鞦鞧鮂鯄鰌鰍鰽鳅鶖鹙鼽龝𨱇', + 'Qu' => '㖆㘗㜹㠊㣄㧁㫢㭕㯫㰦㲘㸖㻃䁦䂂䆽䈌䋧䒧䒼䓚䓛䖦䝣䞤䟊䠐䢗䧢䵶䶚伹佉佢刞劬匤区區厺去取呿唟坥娶屈岖岨岴嶇忂憈戵抾敺斪曲朐欋氍浀淭渠灈璖璩癯瞿磲祛竘竬筁籧粬紶絇翑耝胊胠臞菃葋蕖蘧蛆蛐蝺螶蟝蠷蠼衐衢袪覰覷覻觑詓詘誳诎趋趣趨躣躯軀軥迲鑺镼閴闃阒阹駆駈驅驱髷魼鰸鱋鴝鸜鸲麮麯麴麹黢鼁鼩齲龋', + 'Quan' => '㒰㒽㟫䀬䄐䅚䊎䌯䑏䟒䠰佺全券劝勧勸啳圈圏埢奍姾婘孉峑巏弮恮悛惓拳搼权棬椦楾権權汱泉洤湶烇牶牷犈犬犭瑔畎痊硂筌絟綣縓绻荃葲虇蜷蠸觠詮诠跧踡輇辁醛銓鐉铨闎韏顴颧駩騡鬈鰁鳈齤', + 'Que' => '㕁㩁㰌㱋㱿㲉㴶㹱㾡䇎䍳䦬䧿䲵却卻埆塙墧崅悫愨慤搉榷燩琷瘸皵硞确碏確碻礐礭缺蒛趞闋闕阕阙雀鵲鹊', + 'Qun' => '㟒㪊㿏䭽囷夋宭峮帬羣群裙裠逡𤸷', + 'Ran' => '㒄㚩㜣㲯㸐㾆㿵䎃䒣䔳䕼䖄䣸䤡䫇䳿冄冉呥嘫姌媣染橪然燃珃繎肰苒蒅蚦蚺衻袇袡髥髯𤡮', + 'Rang' => '䉴䑋儴勷嚷壌壤懹攘瀼爙獽瓤禳穣穰纕蘘譲讓让躟鬤', + 'Rao' => '㑱㹛娆嬈扰擾桡橈繞绕荛蕘襓遶隢饒饶', + 'Re' => '惹热熱', + 'Ren' => '㠴㣼㶵㸾䀔䇮䋕䌾䏕䛘䭃人亻仁仞仭任刃刄壬妊姙屻岃忈忍忎扨朲杒栠栣梕棯牣祍秂秹稔紉紝絍綛纫纴肕腍芢荏荵葚衽袵訒認认讱躵軔轫鈓銋靭靱韌韧飪餁饪魜鵀', + 'Reng' => '㭁㺱䄧䚮仍扔礽芿辸陾𠯹𥾋', + 'Ri' => '䒤囸日釰鈤馹驲', + 'Rong' => '㘇㝐㣑㭜㲓㲝㲨㺎㼸䇀䇯䈶䘬䠜䡆䡥䢇䤊䩸傇冗坈媶嫆嬫宂容峵嵘嵤嶸巆戎搈搑曧栄榕榮榵毧氄溶瀜烿熔爃狨瑢穁穃絨縙绒羢肜茙茸荣蓉蝾融螎蠑褣軵鎔镕駥髶', + 'Rou' => '㽥䐓䧷䰆厹媃宍揉柔楺渘煣瑈瓇禸粈糅肉腬葇蝚蹂輮鍒鞣韖騥鰇鶔', + 'Ru' => '㐵㦺㨎㹘㾒䄾䋈䞕䰰乳侞儒入嗕嚅如媷嬬孺嶿帤扖擩曘杁桇汝洳渪溽濡燸筎縟缛肗茹蒘蓐蕠薷蝡蠕袽褥襦辱邚鄏醹銣铷顬颥鱬鳰鴑鴽', + 'Rua' => '挼', + 'Ruan' => '㓴㮕㼱㽭䎡䓴䙇䞂䪭偄堧壖媆撋朊瑌瓀碝礝緛耎軟輭软阮', + 'Rui' => '㓹㢻㪫㲊䂱䄲䅑䇤䌼䓲䬐叡壡婑枘桵橤汭瑞甤睿緌繠芮蕊蕋蕤蘂蘃蚋蜹銳鋭锐', + 'Run' => '㠈䏰䦞橍润潤瞤膶閏閠闰', + 'Ruo' => '䐞偌叒嵶弱捼楉渃焫爇箬篛若蒻鄀鰙鰯鶸', + 'Sa' => '㒎㚫㪪㽂䊛䙣䬃仨卅挱挲摋撒櫒泧洒潵灑脎萨薩虄訯躠鈒钑隡靸颯飒馺𠎷𨆂', + 'Sai' => '㗷㘔㩙䈢䚡䰄僿嗮嘥噻塞愢揌毢毸簺腮賽赛顋鰓鳃', + 'San' => '㤾㧲㪔㪚䈀䉈䊉䫅䫩三仐伞俕傘厁叁壭帴弎散橵毵毶毿犙糁糂糝糣糤繖鏒鏾閐霰饊馓鬖𦙱', + 'Sang' => '䘮䡦䫙丧喪嗓搡桑桒槡磉褬鎟顙颡', + 'Sao' => '㛮㥰㲧㿋䕅埽嫂慅扫掃掻搔氉溞瘙矂繅缫臊螦騒騷骚髞鰠鱢鳋𠋺𤢖𩫦', + 'Se' => '㒊㥶㱇㻭䉢䔼䨛啬嗇懎擌栜歮歰洓涩渋澀澁濇濏瀒琗瑟璱瘷穑穡穯繬色譅轖銫鏼铯閪雭飋𥻨', + 'Sen' => '森椮槮襂', + 'Seng' => '䒏僧鬙', + 'Sha' => '㠺㰱㰼㲚㵤㸺䈉䝊䤬䬊乷倽傻儍刹剎厦唦唼啑啥喢帹廈杀桬榝樧歃殺毮沙煞猀痧砂硰箑粆紗繌纱翜翣莎萐蔱裟鎩铩閯霎魦鯊鯋鲨', + 'Shai' => '㩄㬠㴓䵘晒曬筛篩簁簛繺酾釃閷', + 'Shan' => '㚒㣌㣣㨛㪎㪨㰑㴸㶒㺑䀐䄠䘰䚲䠾䡪䥇䦂䦅䱇䱉䴮傓僐删刪剡剼善嘇圸埏墠墡姍姗嬗山幓彡扇挻掞搧擅敾晱杉柵椫樿檆歚汕潬潸澘灗炶煔煽熌狦珊疝痁睒磰笘縿繕缮羴羶脠膳膻舢芟苫蟮蟺衫覢訕謆譱讪贍赡赸跚軕邖鄯釤銏鐥钐閃閊闪陕陝饍騸骟鯅鱓鱔鳝𥊀𦘹𫮃', + 'Shang' => '䵰䵼丄上伤傷商垧墒尙尚恦慯扄晌殇殤滳漡熵緔绱蔏螪裳觞觴謪賞贘赏鑜鞝鬺', + 'Shao' => '㪢㲈㸛䈰䈾䏴䒚䔠䙼䬰劭勺卲哨娋少弰捎旓柖梢潲烧焼燒玿睄稍筲紹綤绍艄芍苕莦蕱蛸袑輎邵韶颵髾鮹𥳓', + 'She' => '㓭㴇㵃䀅䄕䜓䞌䠶䤮䬷佘厍厙奢射弽慑慴懾捨摂摄摵攝檨欇歙涉涻渉滠灄猞畬畲社舌舍舎蔎虵蛇蛥蠂設设賒賖赊赦輋韘騇麝', + 'Shei' => '谁', + 'Shen' => '㑗㕥㚞㚨㜪㮱㰂㰮㵕㾕䅸䆦䯂䰠什伸侁侺兟呻哂堔妽姺娠婶嬸审宷審屾峷弞愼慎扟敒昚曋曑柛棽椹榊氠涁深渖渗滲瀋燊珅甚甡甧申瘆瘮眒眘瞫矤矧砷神祳穼籶籸紳绅罙罧肾胂脤腎莘葠蓡蔘薓蜃蜄裑覾訠訷詵諗讅诜谂谉身邥鋠頣駪魫鯓鯵鰰鰺鲹鵢𣿇𨴐𬬹𬳽', + 'Sheng' => '㗂㮐㱡㼳㾪䁞䚇䞉䪿䱆䲼䴤偗剩剰勝升呏圣墭声嵊憴斘昇晠曻枡栍榺橳殅泩渻湦焺牲狌珄琞生甥盛省眚竔笙縄繩绳聖聲胜苼蕂譝貹賸鉎鍟阩陞陹鵿鼪', + 'Shi' => '㒾㔺㕜㖷㱁㳏㵓㸷㹝㹬㹷䁺䂖䂠䄷䈕䊓䌤䌳䏉䏡䒨䖨䗐䙾䛈䟗䤭䤱䦹䩃䭄䲽䴓䶡世丗乨乭亊事仕似佦使侍兘冟势勢匙十卋叓史呞呩嗜噬埘塒士失奭始姼媞嬕实実室宩寔實尸屍屎峕崼嵵市师師式弑弒徥忕恀恃戺拭拾揓施时旹是昰時枾柹柿栻榁榯氏浉湜湤湿溡溮溼澨濕炻烒煶狮獅瑡眂眎眡睗矢石示礻祏竍笶筮篒簭籂絁舐舓莳葹蒒蒔蓍虱蚀蝕蝨螫褷襫襹視视觢試詩誓諟諡謚識识试诗谥豉豕貰贳軾轼辻适逝遈適遾邿釈释釋釶鈰鉂鉃鉇鉈鉐鉽銴鍦铈食飠飾餙餝饣饰駛驶鮖鯴鰘鰣鰤鲥鲺鳲鳾鶳鸤鼫鼭', + 'Shou' => '㖟㝊㥅㧃䛵䭭兽収受售垨壽夀守寿手扌授收涭狩獣獸痩瘦綬绶膄艏鏉首', + 'Shu' => '㑐㒔㛸㜐㡏㣽㫹㯮㵂㶖㷂㸡㻿㼡㽰㾁䃞䉀䑕䘤䜹䝂䝪䞖䠼䢞䢤䨹䩱䱙䴰书侸倏倐儵叔咰塾墅姝婌孰尌尗属屬庶庻怷恕戍抒捒掓摅攄数數暏暑曙書朮术束杸枢树梳樞樹橾殊殳毹毺沭淑漱潄潻澍濖瀭焂熟瑹璹疎疏癙秫竖竪糬紓絉綀纾署腧舒荗菽蒁蔬薥薯藷虪蜀蠴術裋襡襩豎贖赎跾踈軗輸输述鄃鉥錰鏣陎隃鮛鱪鱰鵨鶐鸀黍鼠鼡', + 'Shua' => '㕞刷唰耍誜', + 'Shuai' => '㲤䢦卛帅帥摔甩蟀衰', + 'Shuan' => '䧠拴栓涮腨閂闩', + 'Shuang' => '㕠㦼䉶䌮䔪䗮䝄䫪双塽孀孇慡樉欆漺灀爽礵縔艭鏯雙霜騻驦骦鷞鸘鹴', + 'Shui' => '㥨㽷䬽䭨䳠帨水氵氺涗涚睡瞓祱稅税脽裞誰閖', + 'Shun' => '㥧䀢䀵䑞䴄吮橓瞚瞬舜蕣順顺鬊', + 'Shuo' => '㮶䀥䁻哾妁搠朔槊欶烁爍獡矟硕碩箾蒴說説说鎙鑠铄𠲿', + 'Si' => '㕽㚶㟃㠼㣈㭒㴲㸻㹑㺇㺨㽄䇁䇃䎣䏤䔮䡳䦙䫢䲉丝亖佀価俬儩兕凘厮厶司咝嗣嘶噝四姒娰媤孠寺巳廝思恖撕斯杫柶楒榹死汜泀泗泤洍涘澌瀃燍牭磃祀禗禠禩私竢笥籭糹絲緦纟缌罳耜肂肆蕬蕼虒蛳蜤螄蟖蟴覗貄釲鈶鈻鉰銯鋖鐁锶颸飔飤飼饲駟騦驷鷥鸶鼶', + 'Song' => '㞞㣝㧐㨦㩳㮸䉥䛦䜬䢠䯳䯷倯傱凇娀宋崧嵩嵷庺忪怂悚愯慫憽松枀枩柗梥楤檧淞濍硹竦耸聳菘蜙訟誦讼诵送鍶鎹頌颂餸駷鬆𧊕𩠌𪀚', + 'Sou' => '㛐㟬䈭䈹䉤䏂䐹䑹䗏䤹䩳䬒䮟䱸傁凁叜叟嗖嗽嗾廀廋捜搜摉摗擞擻櫢溲獀瘶瞍籔艘蒐蓃薮藪螋鄋醙鎪锼颼颾飕餿馊騪', + 'Su' => '㑉㑛㓘㔄㕖㜚㝛㢝㨞㪩㬘㯈㲞㴋㴑㴼䃤䅇䌚䎘䏋䑿䔎䛾䥔䲆俗傃僳嗉囌塐塑夙嫊宿愫愬憟梀榡樎樕橚櫯殐泝洬涑溯溸潚潥玊珟璛甦碿稣穌窣簌粛粟素縤肃肅膆苏莤蔌藗蘇蘓觫訴謖诉谡趚蹜速遡遬酥鋉餗驌骕鯂鱐鷫鹔𤠚𫗧', + 'Suan' => '䝜匴狻痠祘笇筭算蒜酸', + 'Sui' => '㒸㞸㥞㴚㵦㻟㻪㻽䅗䉌䍁䔹䜔䠔䡵䢫䥙䧌䪎䭉䯝亗倠哸埣夊嬘岁嵗旞檖歲歳浽滖澻濉瀡煫熣燧璲瓍眭睟睢砕碎祟禭穂穗穟綏繀繐繸绥膸芕荽荾葰虽襚誶譢谇賥遀遂邃鐆鐩隋随隧隨雖鞖韢髄髓', + 'Sun' => '㔼㦏䁚䐣孙孫损損搎榫槂狲猻笋筍箰簨荪蓀蕵薞鎨隼飧飱鶽𦠆', + 'Suo' => '㛖㪽㮦䂹䅴䈗䐝䓾䔋䖛䞆䞽䣔䯯䵀乺傞唆唢嗍嗦嗩娑惢所摍暛桫梭溑溹琐琑瑣璅睃簑簔索縮缩羧莏蓑蜶褨趖逤鎈鎍鎖鎻鏁锁髿鮻', + 'Ta' => '㒓㗳㛥㣛㣵㧺㭼㯓㯚㳠㹺㺚㿹䂿䈋䈳䌈䍇䍝䎓䑜䑽䓠䜚䳴䵬䶀䶁他侤咜嚃嚺塌塔墖她它崉拓挞搨撻榙榻橽毾涾溚溻澾濌牠狧獭獺祂禢褟誻譶趿踏蹋蹹躢遝遢錔铊闒闥闧闼鞜鞳鮙鰨鳎鿎', + 'Tai' => '㑷㒗㘆㙵㣍㥭㬃㷘㸀䈚䑓䣭儓冭台囼坮太夳嬯孡忲态態抬擡旲枱檯汰泰溙炱炲燤箈籉粏肽胎臺舦苔菭薹跆邰酞鈦钛颱駘鮐鲐', + 'Tan' => '㘱㛶㨏㫜㲜㲭㳩㴂㵅㷋㽎㽑䃪䆱䉡䊤䏙䐺䑙䕊䗊䜖䞡䦔倓傝僋叹嗿嘆坍坛坦埮墰墵壇壜婒忐怹惔憛憳憻探摊擹攤昙暺曇榃檀歎毯湠滩潭灘炭燂璮痑痰瘫癱碳磹罈罎舑舕菼藫袒襢覃談譚譠谈谭貚貪賧贪郯醈醓醰鉭錟钽锬顃餤𠻪𨅍𩑰', + 'Tang' => '㑽㒉㓥㙶㜍㭻㲥㼒㼺㿩䅯䉎䌅䕋䞶䟖䠀䣘䧜伖倘偒傏傥儻劏唐啺嘡坣堂塘帑戃搪摥曭棠榶樘橖汤淌湯溏漟烫煻燙爣瑭矘磄禟篖糃糖糛羰耥膅膛蓎薚蝪螗螳赯趟踼蹚躺鄌醣鎕鎲鏜鐋钂铴镋镗闛隚鞺餳餹饄饧鶶鼞𦳝', + 'Tao' => '㚐㣠㫦㹗䀞䄻䈱䑬䚯䛌䛬䤾䬞䵚匋咷啕夲套嫍幍弢慆掏搯桃梼槄檮洮涛淘滔濤瑫祹絛綯縚縧绦绹萄蜪裪討詜謟讨轁迯逃醄鋾錭陶鞀鞉鞱韜韬飸饀饕駣騊鼗', + 'Te' => '㥂㧹忑忒慝特螣蟘貣鋱铽', + 'Teng' => '䒅䕨䠮䲍䲢儯幐滕漛熥疼痋籐籘縢腾膯藤虅誊謄邆霯駦騰驣鰧鼟', + 'Ti' => '㔸㖒㗣㡗㣢㬱㯩䅠䌡䎮䔶䖙䙗䚣䛱䢰䨑䪆䬫䬾䯜䱱䴘䶏䶑体倜偍剃剔厗啼嗁嚏嚔屉屜崹徲悌悐惕惖惿戻挮掦提揥擿替朑梯楴歒殢洟涕漽瑅瓋碮禵稊笹籊綈緹绨缇罤苐荑蕛薙蝭裼褅褆謕趧趯踢蹄蹏躰軆逖逷遆醍銻鍗锑題题騠骵體髰鬀鮧鮷鯷鳀鴺鵜鶗鶙鷈鷉鷤鹈', + 'Tian' => '㐁㖭㙉㥏㧂㬲㮇㶺䀖䄼䄽䋬䐌䑚䚶䟧䠄䡒䡘䥖䧃倎兲唺塡填天婖屇忝恬悿掭搷晪殄沺淟添湉琠璳甛甜田畋畑畠痶盷睓睼碵磌窴緂胋腆舔舚菾覥觍賟酟鈿錪鍩闐阗靔靝靦餂鴫鷆鷏黇', + 'Tiao' => '㟘㬸㸠䒒䖺䟭䠷䩦䯾䱔佻嬥宨岧岹庣恌挑斢旫晀朓条條樤眺祒祧窕窱笤粜糶絩聎脁芀萔蓚蓨蜩螩覜誂趒跳迢鋚鎥鞗髫鯈鰷鲦齠龆', + 'Tie' => '䥫䩞䴴䵿僣呫帖怗聑萜蛈貼贴銕鋨鐡鐵铁飻餮驖鴩', + 'Ting' => '㓅㹶㼗䅍䋼䗴䦐䯕䱓䵺亭侹停厅厛听圢娗婷嵉庁庭廰廳廷挺桯梃楟榳汀涏渟烃烴烶珽町甼筳綎耓聤聴聼聽脡艇艼莛葶蜓蝏誔諪邒閮霆鞓頲颋鼮', + 'Tong' => '㛚㠉㠽㣚㤏㪌㸗㼧㼿䂈䆚䮵䳋䴀䶱仝佟僮勭同哃嗵囲峂峝庝彤恸慟憅捅晍曈朣桐桶樋橦氃浵潼炵烔燑犝狪獞痌痛眮瞳砼秱童筒筩粡統綂统膧茼蓪蚒衕詷赨通酮鉖鉵銅铜餇鮦鲖', + 'Tou' => '㓱㖣㢏㪗㳆㼥䕱䚵䞬䟝䱏䵉亠偷偸头妵婾媮投敨紏綉緰蘣透鋀鍮钭頭飳骰黈𡷠𩜶', + 'Tu' => '㟮㭸㻌㻠㻬㻯䅷䖘䛢䞮䠈䣄䣝䤅䩣䳜兎兔凃凸吐唋図图圕圖圗土圡堍堗塗宊屠峹嵞嶀庩廜徒怢悇捈捸揬梌汢涂涋湥潳痜瘏禿秃稌突筡腯荼莵菟葖蒤跿迌途酴釷鈯鋵鍎钍馟駼鵌鵚鵵鶟鷋鷵鼵', + 'Tuan' => '㩛䊜䜝䝎䵊䵎䵯剸团団團彖慱抟摶槫檲湍湪漙煓猯疃篿糰褖貒鏄鷒鷻', + 'Tui' => '㞂㞜㢈㢑㥆㱣㷟㾼㿉㿗䀃䅪侻俀僓娧尵弚推煺穨腿蓷藬蘈蛻蜕褪蹆蹪退隤頹頺頽颓駾骽魋𠺙𬯎', + 'Tun' => '㖔㧷㩔㬿㹠㼊吞呑啍噋坉屯忳旽暾朜氽涒焞畽臀臋芚豘豚軘霕飩饨魨鲀黗𧑒𩂄', + 'Tuo' => '㟎㸰㸱㼠㾃䍫䓕䜏䡐䪑䭾䰿䴱乇仛佗侂咃唾坨堶妥媠嫷岮庹彵托扡拕拖挩捝杔柝椭楕槖橐橢毤毻汑沰沱沲涶狏砣砤碢箨籜紽脫脱莌萚蘀袉袥託讬跅跎迱酡陀陁飥饦馱駄駝駞騨驒驝驮驼鬌魠鮀鰖鴕鵎鸵鼉鼍鼧𨁡𬶍', + 'Wa' => '㧚㼘䍪䎳䚴䠚䨟䯉䵷佤劸咓哇嗗嗢娃娲媧屲挖搲攨洼溛漥瓦瓲畖砙穵窊窪聉腽膃蛙袜襪邷韈韤鼃', + 'Wai' => '㖞㗏䠿䴜䶐喎外夞崴歪竵顡', + 'Wan' => '㘤㜶㝴㸘㽜㿸䅋䑱䖤䗕䘎䘼䛃䛷䝹䥑䩊䯈䯛䳃万丸倇刓剜卍卐唍埦塆壪妧婉婠完宛岏帵弯彎忨惋抏挽捖捥晚晥晩晼杤梚椀汍湾潫澫灣烷玩琓琬畹皖盌睕瞣碗笂紈綩綰纨绾翫脕脘腕芄菀萖萬薍蜿蟃豌貦贃贎踠輐輓鋄鋔錽鎫頑顽𬇕', + 'Wang' => '㓁㲿㳹㴏䋄䋞䒽䤑䰣亡亾仼兦妄尣尩尪尫彺往徃徍忘惘旺暀望朢枉棢汪瀇王盳網网罒罔莣菵蚟蛧蝄誷輞辋迋魍', + 'Wei' => '㕒㖐㙎㙔㙗㛱㞇㞑㟪㠕㣦㣲㥜㦣㨊㬙㭏㮃㱬㷉䃬䇻䈧䉠䊊䋿䍴䍷䑊䔺䗽䘙䙟䙿䜅䜜䝐䞔䡺䥩䦱䧦䪋䪘䫋䬑䬿䭳䮹䲁䴧䵋䵳为伟伪位偉偎偽僞儰卫危厃叞味唯喂喡喴囗围圍圩墛壝委威娓媁媙媦寪尉尾屗峗峞崣嵔嵬嶶巍帏帷幃徫微惟愄愇慰懀捤揋揻撱斖暐未桅梶椲椳楲欈沩洈洧浘涠渨渭湋溈溦潍潙潿濰濻瀢炜為烓煀煒煟煨熭燰爲犚犩猥猬玮琟瑋璏畏痏痿癓硊硙碨磈磑維緭緯縅纬维罻胃腲艉芛苇苿荱菋萎葦葨葳蒍蓶蔚蔿薇薳藯蘶蜲蜼蝛蝟螱衛衞褽覣覹詴諉謂讆讏诿谓踓躗躛軎轊违逶違鄬醀鍏鍡鏏闈闱隇隈霨霺韋韑韙韡韦韪頠颹餧餵饖骩骪骫魏鮇鮠鮪鰃鰄鲔鳂鳚', + 'Wen' => '㗃㝧㡈㬈㼔䎹䎽䐇䘇䦟䰚刎匁吻呚呡問塭妏彣忟抆揾搵文昷桽榅榲殟汶渂温溫炆玟珳瑥璺瘒瘟稳穏穩紊紋纹聞肳脗芠莬蕰蚉蚊螡蟁豱輼轀辒鎾閺閿闅闦问闻阌雯鞰顐饂馼駇魰鰛鰮鳁鳼鴍鼤', + 'Weng' => '㘢㜲㮬㹙㺋䈵䐥䩺䱵勜嗡塕奣嵡攚暡滃瓮甕瞈罋翁聬蓊蕹螉鎓鶲鹟齆𬭩', + 'Wo' => '㠛㦱㧴㱧㹻䀑䁊䂺䠎䮸䰀仴倭偓卧唩婐媉幄我挝捰捾握撾擭斡枂楃沃涡涴涹渥渦濣焥猧瓁瞃硪窝窩肟腛臒臥莴萵蜗蝸踒雘齷龌', + 'Wu' => '㐅㐳㑄㒇㡔㬳㮧㵲㷻㹳㻍㽾䃖䉑䍢䎸䑁䒉䓊䖚䛩䜑䟼䡧䦍䦜䨁䫓䮏䳇䳱乄乌五仵伆伍侮俉倵儛兀剭务務勿午卼吳吴吾呉呒呜唔啎嗚圬坞塢奦妩娪娬婺嫵寤屋屼岉嵍嵨巫庑廡弙忢忤怃悞悟悮憮戊扤捂摀敄无旿晤杇杌梧橆歍武毋汙汚污洖洿浯溩潕烏焐無熃熓物牾玝珷珸瑦璑甒痦矹碔祦禑窏窹箼粅舞芜芴茣莁蕪蘁蜈螐蟱誈誣誤譕诬误躌迕逜邬郚鄔鋈錻鎢钨铻阢隖雺雾霚霧靰騖骛鯃鰞鴮鵐鵡鶩鷡鹀鹉鹜鼯鼿齀', + 'Xi' => '㑶㓾㔒㕃㕧㗩㗭㘊㙾㚀㚛㛓㛫㛭㜎㜯㠄㣟㤸㦦㦻㩗㪧㬛㭡㮩㯕㰥㰿㱆㱤㲸㴔㴧㶉㸍㺣㽯㾷㿇㿽䀌䁯䂀䈪䊠䏩䏮䐅䐖䐼䒁䒊䓇䖒䖷䙵䚫䛊䛥䜁䢄䧍䨳䫣䬣䭒䮎䲪䳶䵱䶋习係俙傒僖兮凞匸卌卥厀吸呬咥唏唽喜喺嘻噏嚱囍墍壐夕奚媳嬆嬉屃屖屣屭嵠嶍嶲巇希席徆徙徯忚忥怬怸恄恓息悉悕惁惜慀憘憙戏戱戲扱扸昔晞晰晳暿曦析枲桸椞椺榽槢樨橀橲檄欯欷歖氥汐洗浠淅渓溪滊漇漝潝潟澙烯焁焈焟焬煕熂熄熈熙熹熺熻燨爔牺犀犔犠犧狶玺琋璽瘜皙盻睎瞦矖矽硒磎磶礂禊禧稀稧穸窸粞糦系細綌緆縘縰繥繫细绤羲習翕翖肸肹膝舃舄舾莃菥葈葸蒠蒵蓆蓰蕮薂虩蜥螅螇蟋蟢蠵衋袭襲西覀覡覤觋觹觽觿諰謑謵譆谿豀豨豯貕赥赩趇趘蹝躧邜郋郗郤鄎酅醯釳釸鈢鉨鉩錫鎴鏭鑴铣锡闟阋隙隟隰隵雟霫霼飁餏餼饩饻騱騽驨鬩鯑鰼鱚鳛鵗鸂黖鼷𠅤𠩺𡏛', + 'Xia' => '㔠㗇㘡㙈㙤㰨㰰㰺㽠䖎䖖䘥䛅䠍䪗䫗丅下乤侠俠傄匣吓嚇圷夏夓峡峽懗敮暇柙梺炠烚煆狎狭狹珨瑕疜疨睱瞎硖硤碬磍祫筪縀縖罅翈舝舺蕸虲虾蝦谺赮轄辖遐鍜鎋鎼鏬閕閜陜陿霞颬騢魻鰕鶷黠', + 'Xian' => '㔾㘅㘋㛾㡉㡾㢺㦑㦓㧥㪇㫫㬎㬗㭠㭹㮭㯗㰊㰹㲔㳄㳭㵪㶍㷿㸝㺌㺤㽉㾾㿅㿌䁂䂅䃱䃸䄳䆎䉯䉳䊱䏹䐄䕔䗾䘆䙹䚚䜢䝨䢾䤼䥪䦘䦥䧋䧟䧮䨘䨷䩂䯭䯹䱤䲗䵇䵌䶟仙仚伣伭佡僊僩僲僴先冼县咞咸哯唌啣嘕垷壏奾妶姭娊娨娴娹婱嫌嫺嫻嬐宪尟尠屳岘峴崄嶮幰廯弦忺憪憲憸挦掀搟撊撏攇攕显晛暹杴枮橌櫶毨氙涀涎湺澖瀗灦烍燹狝猃献獫獮獻玁现珗現甉痫癇癎県睍瞯硍礥祆禒秈稴筅箲籼粯糮絃絤綫線縣繊纎纖纤线缐羡羨胘腺臔臽舷苋苮莧莶薟藓藖蘚蚬蚿蛝蜆衔衘褼襳誢誸諴譣豏賢贒贤赻跣跹蹮躚輱酰醎銑銛銜鋧錎鍁鍌鑦铦锨閑閒闲限陥险陷険險韅韯韱顕顯餡馅馦鮮鱻鲜鶱鷳鷴鷼鹇鹹麙麲鼸', + 'Xiang' => '㐮㗽㟄㟟䊑䐟䔗䖮䜶䢽䦳䬕䴂乡享亯佭像勨厢向响啌嚮塂姠嶑巷庠廂忀想晑曏栙楿橡欀湘珦瓖瓨相祥稥箱絴緗缃缿翔膷芗萫葙薌蚃蟓蠁衖襄襐詳详象跭郷鄉鄊鄕銄銗鐌鑲镶響項项飨餉饗饟饷香驤骧鮝鯗鱌鱜鱶鲞麘𢪷𬙋', + 'Xiao' => '㔅㕺㗛㚠㚣㤊㩋㪣㬵㮁㲖㵿㹲㺒䉰䊥䌃䎄䒕䒝䕧䟁䥵䨭䬘䴛侾俲傚効呺咲哓哮啸嘋嘐嘨嘯嘵嚣嚻囂婋孝宯宵小崤庨彇恷憢揱效敩斅斆晓暁曉枭枵校梟櫹歊歗殽毊洨消涍淆潇瀟灱灲焇熽猇獢痚痟皛皢硝硣穘窙笑筊筱筿箫篠簘簫綃绡翛肖膮萧萷蕭藃虈虓蟂蟏蟰蠨訤詨誟誵謏踃逍郩銷销霄驍骁髇髐魈鴞鴵鷍鸮', + 'Xie' => '㐖㒠㓔㔎㕐㖑㖿㗨㙝㙦㙰㝍㞒㞕㡜㢵㣯㣰㥟㦪㨙㨝㩦㩪㭨㰔㰡㱔㳦㳿㴬㴮㴽㸉㽊㾚䀘䁋䉏䉣䊝䔑䕈䕵䙊䙎䙝䙽䚸䝱䡡䥱䥾䦏䦖䩤䩧䪥䲒䵦些亵伳偕偞偰僁写冩劦勰协協卨卸嗋噧垥塮夑奊娎媟寫屑屓屟屧峫嶰廨徢恊愶懈拹挟挾揳携撷擕擷攜斜旪暬械楔榍榭歇泄泻洩渫澥瀉瀣灺炧炨烲焎熁燮燲爕猲獬瑎祄禼糏紲絏絬綊緤緳繲纈绁缬缷翓胁脅脇脋膎薢薤藛蝎蝢蟹蠍蠏衺褉褻襭諧謝讗谐谢躞邂邪鞋鞢鞵韰頡齂齘齛齥龤', + 'Xin' => '㐰㔤㚯㛙㛛㜦㭄㭢㾙䅽䒖䚱䛨䜗䜣伈伩信俽噺囟妡嬜孞廞心忄忻惞新昕杺枔欣歆炘焮盺脪舋芯薪衅襑訢訫軐辛邤釁鈊鋅鐔鑫锌阠顖馨馫馸', + 'Xing' => '㐩㓑㓝㙚㝭㣜㨘㷣㼛㼬䁄䂔䃏䓷䕟䗌䛭䣆䤯䰢䳙侀倖兴刑哘型垶姓娙婞嬹幸形性悻惺擤星曐杏洐涬滎煋猩瑆皨睲硎箵篂緈腥臖興荇荥莕蛵行裄觪觲謃邢郉醒鈃鉶銒鋞钘铏陉陘騂骍鮏鯹', + 'Xiong' => '㐫㚾䧺兄兇凶匂匈哅夐忷恟敻汹洶焸焽熊胷胸訩詗詾讻诇賯雄', + 'Xiu' => '㗜㱗㱙㳜㵻㹋㾋䏫䐰䗛䡭休俢修咻嗅岫峀庥朽樇溴滫潃烋烌珛琇璓秀糔綇繍繡绣羞脙脩臹苬螑袖褎褏貅銝銹鎀鏅鏥鏽锈飍饈馐髤髹鮴鱃鵂鸺齅', + 'Xu' => '㐨㑔㑯㕛㖅㗵㘧㜅㜿㞊㞰㥠㰭㳚㵰㷦㺷㽳䂆䅡䇓䈝䋶䍱䎉䏏䔓䘏䙒䛙䢕䣱䣴䦗䦽䧁䬄䱬䳳伵侐俆偦冔勖勗卹叙吁呴喣嘘噓垿墟壻姁婿媭嬃幁序徐怴恤慉戌揟敍敘旭旴昫晇暊朂栩楈槒欨欰歔殈汿沀洫湑溆漵潊烅烼煦獝珝珬疞盢盨盱瞁瞲稰稸窢糈絮続緒緖縃繻續绪续聓聟胥芧蒣蓄蓿蕦藇藚虗虚虛蝑裇訏許訹詡諝譃许诩谞賉鄦酗醑銊鑐需須頊须顼驉鬚魆魖魣鱮', + 'Xuan' => '㓩㔯㔵㘣㝁㦥㧋㧦㩊㯀㳙㳬㹡㻹㾌䀏䁔䁢䃠䆭䍗䍻䗠䚙䚭䝮䠣䧎䩙䩰䮄䲂䲻䳦儇吅咺喧塇媗嫙宣弲怰悬愃愋懁懸揎旋昍昡晅暄暶梋楥楦檈泫渲漩炫烜煊玄玹琁琄瑄璇璿痃癣癬眩眴睻矎碹禤箮絢縇縼繏绚翧翾萱萲蓒蔙蕿藼蘐蜁蝖蠉衒袨諠諼譞讂谖贙軒轩选選鉉鋗鍹鏇铉镟鞙顈颴駽鰚', + 'Xue' => '㕰㖸㗾㞽㰒㶅㻡㿱䆝䆷䋉䎀䒸䛎䤕䦑䨮䫼䬂䭥䱑乴削吷坹壆学學岤峃嶨斈桖樰泶澩瀥燢狘疶穴膤艝茓蒆薛血袕觷謔谑趐踅轌辥辪雤雪靴鞾鱈鳕鷽鸴', + 'Xun' => '㖊㜄㡄㢲㨚㰬㵌㽦䋸䖲䗼䘩䙉䛜䞊䠝䭀䵫伨侚偱勋勛勲勳卂噀噚嚑坃埙塤壎壦奞寻尋峋巡巺巽廵徇循恂愻揗攳旬曛杊栒桪樳殉殾毥汛洵浔潠潯灥焄熏燅燖燻爋狥獯珣璕畃矄稄窨紃纁臐荀荨蔒蕈薫薰蘍蟳訊訓訙詢训讯询賐迅迿逊遜鄩醺鑂顨馴駨驯鱏鱘鲟𠊫𫄸𬊈𬍤𬘓𬩽', + 'Ya' => '㝞㧎㰳㳌㾎㿿䃁䄰䅉䆘䝟䢝䦪䪵䰲丫乛亚亜亞伢俹劜厊压厑厓吖呀哑唖啞圔圠圧垭埡堐壓娅婭孲岈崕崖庌庘押挜掗揠枒桠椏氩氬涯漄牙犽猚猰玡琊瑘痖瘂睚砑稏窫笌聐芽蕥蚜衙襾訝讶軋轧迓錏鐚铔雅鴉鴨鵶鸦鸭齖齾𡴭𪘲', + 'Yan' => '㕣㖶㗴㘖㘙㚧㛪㝚㢂㢛㤿㦔㫃㫟㬫㭺㮒㰽㳂㶄㷔㷳㷼㸶㺂㿕㿼䀋䀽䁙䂩䂴䄋䅧䇾䉷䊙䌪䍾䎦䑍䓂䖗䗎䗡䗺䛳䜩䞁䞛䢥䢭䣍䤷䦲䨄䫡䲓䳛䳡䳺䴏䶫䶮严乵俨偃偐偣傿儼兖兗剦匽厌厣厭厳厴咽唁啱喭噞嚥嚴堰塩墕壛壧夵奄妍妟姲姸娫娮嫣嬊嬮嬿孍宴岩崦嵃嵒嵓嶖巌巖巗巘巚延弇彥彦恹愝懕懨戭扊抁掩揅揜敥昖晏暥曕曣曮棪椻椼楌樮檐檿櫩欕沇沿淊淹渰渷湮溎滟演漹灎灔灧灩炎烟烻焉焑焔焰焱煙熖燄燕爓牪狿猒珚琂琰甗盐眼研砚硏硯硽碞礹筵篶簷綖縯罨胭腌臙艳艶艷芫莚菸萒葕蔅虤蜒蝘衍裺褗覎觃觾言訁訮詽諺讌讞讠谚谳豓豔贋贗赝躽軅遃郔郾鄢酀酓酽醃醶醼釅閆閹閻闫阉阎隁隒雁顏顔顩颜餍饜騐験騴驗驠验鬳魇魘鰋鳫鴈鴳鶠鷃鷰鹽麣黡黤黫黬黭黶鼴鼹齞齴龑', + 'Yang' => '㒕㔦㟅㦹㨾㬕㺊㿮䁑䍩䑆䒋䖹䬗䬺䭐䱀䵮仰佒佯傟养劷咉坱垟央姎岟崵崸徉怏恙慃懩扬抰揚攁敭旸昜暘杨柍样楊楧様樣殃氜氧氱泱洋漾瀁炀炴烊煬珜疡痒瘍癢眏眻礢禓秧紻羊羏羕羪胦蛘蝆詇諹軮輰鉠鍚鐊钖阦阳陽雵霷鞅颺飏養駚鰑鴦鴹鸉鸯𠍵𡡂𥒞', + 'Yao' => '㑸㑾㔽㙘㝔㞁㟱㢓㨱㫏㫐㴭㵸㹓㿑㿢䁏䁘䂚䆗䆙䆞䋂䌁䌊䌛䔄䖴䙅䚺䚻䛂䠛䢣䬙䯚䳩䴠䶧仸倄偠傜吆咬喓嗂垚堯夭妖姚婹媱宎尧尭岆峣崾嶢嶤幺徭愮抭揺搖摇摿暚曜杳枖柼楆榚榣殀溔滧烑熎燿爻狕猺獟珧瑤瑶眑矅磘祅穾窅窈窑窔窯窰筄繇纅耀肴腰舀艞苭药葯葽蓔薬藥蘨袎要覞訞詏謠謡讑谣軺轺遙遥邀邎銚鎐鑰钥闄靿顤颻飖餆餚騕鰩鳐鴁鴢鷂鷕鹞鼼齩', + 'Ye' => '㖡㗼㙒㡋㥷㩎㪑㱉㱌㸣䁆䈎䊦䎨䓉䢡䤳䤶䥟䥡䥺䧨䭇䭎䭟䱒䲜业也亪亱倻僷冶叶吔啘嘢噎嚈埜堨墷壄夜嶪嶫抴捓捙掖揶擛擨擪擫晔暍曄曅曗曳曵枼枽椰楪業歋殗洂液漜潱澲烨燁爗爷爺璍皣瞱瞸礏耶腋葉蠮謁谒邺鄓鄴野釾鋣鍱鎁鎑鐷铘靥靨頁页餣饁馌驜鵺鸈𣚕', + 'Yi' => '㐌㐹㑊㑜㑥㓷㔴㕈㖂㘁㘈㙠㙪㙯㚤㚦㛄㛕㛳㜋㜒㝖㝣㞔㠖㠯㡫㡼㢞㣇㣻㥋㥴㦉㦤㦾㫊㰘㰝㰻㱅㱞㱲㲼㳑㳖㴁㴒㵝㵩㶠㹫㹭㺿㼢㽈㾨䃜䄁䄩䄬䄿䆿䇩䇵䇼䉗䉝䉨䋚䋵䌻䎈䒾䓃䓈䓹䔟䔬䔱䕍䖁䖊䖌䗑䗟䗷䘝䘸䚷䝘䝝䝯䞅䢃䣡䣧䦴䧅䧇䧧䩟䪰䫑䬁䬥䬮䭂䭞䭲䭿䮊䯆䰙䰯䱌䲑䴊䴬䵝一乁乂义乊乙亄亦亿以仪伇伊伿佁佚佾侇依俋倚偯儀億兿冝刈劓劮勚勩匇匜医吚呓呭呹咦咿唈噫囈圛圯坄垼埶埸墿壱壹夁夷奕姨媐嫕嫛嬄嬑嬟宐宜宧寱寲屹峄峓崺嶧嶬嶷已巸帟帠幆庡廙异弈弋弌弬彛彜彝彞役忆怈怡怿恞悒悘悥意憶懌懿扅扆抑拸挹掜揖撎攺敡敼斁旑旖易晹暆曀曎杙枍枻柂栘栧栺桋棭椅椬椸榏槸檍檥檹欥欭欹歝殔殪殹毅毉沂沶泆洢浂浥浳渏湙溢漪潩澺瀷炈焲熠熤熪熼燚燡燱狋猗獈玴珆瑿瓵畩異疑疫痍痬瘗瘞瘱癔益眙睪瞖矣硛礒祎禕秇移稦穓竩笖箷簃籎縊繄繶繹绎缢羛羠義羿翊翌翳翼耛耴肄肊胰膉臆舣艗艤艺芅苅苡苢萓萟蓺薏藙藝蘙虉蚁蛜蛡蛦蜴螔螘螠蟻衣衤衪衵袘袣裔裛裿褹襼觺訑訲訳詍詑詒詣誃誼謻譩譯議讉讛议译诒诣谊豙豛豷貖貤貽賹贀贻跇跠踦軼輢轙轶辷迆迤迻逘逸遗遺邑郼酏醫醳醷釔釴鈘鈠鉯銥鎰鏔鐿钇铱镒镱陭隿霬靾頉頤頥顊顗颐飴饐饴駅驛驿骮鮨鯣鳦鶂鶃鶍鷁鷊鷖鷧鷾鸃鹝鹢鹥黓黟黳齮齸𠂆𠯋𠲔𠲖𠲺𠼪𡄵𡄻𢏗𢖺𢩮𣐿𤥿𥑴𥜥𦏸𧫦𩓧𩼨𫄷𫖮𬟁𬬩𬺈', + 'Yin' => '㐆㐺㒚㕂㖗㙬㝙㞤㡥㣧㥯㥼㦩㧈㧢㪦㱃㴈㶏㸒㹜㹞䄄䇙䌥䒡䓄䓰䕃䕾䖐䖜䚿䜾䡛䤃䨸䪩䲟䴦乑乚侌冘凐印吟吲喑噖噾嚚囙因圁垔垠垽堙堷夤姻婣婬寅尹峾崟崯嶾廕廴引愔慇慭憖憗懚斦朄栶檃檭檼櫽歅殥殷氤泿洇洕淫淾湚溵滛濥濦烎犾狺猌珢璌瘖瘾癊癮碒磤禋秵筃粌絪緸胤苂茚茵荫荶蒑蔩蔭蘟蚓螾蟫裀訔訚訡誾諲讔赺趛輑鄞酳鈏鈝銀銦铟银闉阥阴陰陻隂隐隠隱霒霠霪靷鞇音韾飮飲饮駰骃鮣鷣齗龂𠃊𣓆𩃬𬘡𬤇𬮱', + 'Ying' => '㑞㡕㢍㨕㲟㵬㶈㹚㹵㿘䀴䁐䁝䃷䊔䑉䓨䕦䙬䚆䣐䤝䤰䦫䧹䨍䪯䬬䭊䭗䭘䴍䵴偀僌啨営嘤噟嚶塋婴媖媵嫈嬰嬴孆孾巊应廮影応愥應摬撄攍攖映暎朠桜梬楹樱櫻櫿浧渶溁溋滢潁潆濙濚濴瀅瀛瀠瀯瀴灐灜煐熒營珱瑛瑩璎瓔甇甖瘿癭盁盈矨硬碤礯穎籝籯緓縈纓绬缨罂罃罌膡膺英茔荧莹莺萤营萦萾蓥藀蘡蛍蝇蝧蝿螢蠅蠳褮覮謍譍譻賏贏赢軈迎郢鍈鎣鐛鑍锳霙鞕韺頴颍颕颖鱦鴬鶑鶧鶯鷪鷹鸎鸚鹦鹰𤇾', + 'Yo' => '哟唷喲', + 'Yong' => '㐯㙲㜉㝘㞲㟾㦷㴄㴩㶲㷏㻾㽫䗤䗸䞻䧡佣俑傛傭勇勈咏喁嗈噰埇塎墉壅嫞嵱庸廱彮怺恿悀惥愑愹慂慵拥揘擁柡栐槦永泳涌湧滽澭灉牅用甬痈癕癰砽硧禜臃苚蛹詠踊踴邕郺鄘醟鏞镛雍雝顒颙饔鯒鰫鱅鲬鳙鷛𩍓', + 'You' => '㒡㓜㕗㕱㗀㘥㚭㛜㤑㫍㮋㰶㱊㳊㳺㴗㶭㹨㺠㽕㾞䀁䅎䆜䍃䑻䒴䖻䚃䛻䞥䢊䢟䥳䬀䱂䳑丣亴优佑侑偤優卣又友右呦哊唀嚘囿姷孧宥尢尤峟峳幼幽庮忧怣怮悠憂懮攸斿有柚栯梄楢槱櫌櫾沋油泑浟游湵滺瀀牖牗牰犹狖猶猷由疣祐禉秞糿纋羐羑耰聈肬脜苃莜莠莸蒏蕕蚰蚴蜏蝣訧誘诱貁輏輶迶逌逰遊邮郵鄾酉酭釉鈾銪铀铕駀魷鮋鱿鲉麀黝鼬𢪥𩲎𬨎', + 'Yu' => '㑨㒁㒜㔱㙑㚜㚥㝢㝼㠘㠨㡰㣃㤢㤤㥔㥚㥥㦛㦽㧒㪀㬂㬰㰲㲾㳛㶛㷒㺄㺞㺮㻀㼌㼶㽣䁌䁩䂊䂛䃋䄏䄨䆰䈅䉛䋖䋭䍂䍞䏸䐳䔡䖇䗨䘘䘱䘻䛕䜡䜽䞝䢓䢖䢩䣁䣿䤋䥏䨒䨞䩒䩽䫻䬔䮇䮙䰻䱷䲣䴁䵥与乻予于亐伃伛余俁俞俣俼偊傴儥兪匬唹喅喐喩喻噊噳圄圉圫域堉堣堬妤妪娛娯娱媀嫗嬩宇寓寙屿峪峿崳嵎嵛嶎嶼庽庾彧御忬悆惐愈愉愚慾懙戫扜扵挧揄敔斔斞於旕旟昱杅桙棛棜棫楀楡楰榆櫲欎欝欤欲歈歟歶毓浴淢淤淯渔渝湡滪漁潏澚澞澦灪焴煜燏燠爩牏狱狳獄玉玗玙琙瑀瑜璵畭瘀瘉瘐癒盂盓睮矞砡硢硲礇礖礜祤禦禹禺秗稢稶穥穻窬窳竽箊篽籅籞籲紆緎繘纡罭羭羽聿肀育腴臾舁舆與艅艈芋芌茟茰萭萮萸蒮蓣蓹蕍蕷薁蘌蘛虞虶蜟蜮蝓螸衧袬裕褕覦觎誉語諛諭謣譽语谀谕豫貐踰軉輍輿轝込迂迃逳逾遇遹邘郁鄅酑醧鈺銉鋊鋙錥鍝鐭钰閾阈陓隅雓雨雩霱預頨预飫餘饇饫馀馭騟驈驭骬髃鬰鬱鬻魊魚鮽鯲鰅鱊鱼鳿鴥鴧鴪鵒鷠鷸鸆鸒鹆鹬麌齬龉龥𡁎𢯮𤸒𤹪𥙿𧶠', + 'Yuan' => '㟶㠾㤪㥐㥳㭇㹉㾓䅈䏍䖠䛄䛇䡝䥉䦾䨊䩩䬇䬧䬼䱲䲮䳒䳣傆元円冤剈原厡厵员員噮囦园圆圎園圓垣垸塬夗妴媛媴嫄嬽寃怨悁惌愿掾援杬棩榞榬橼櫞沅淵渁渆渊渕湲源溒灁爰猨猿獂瑗盶眢禐笎箢緣縁缘羱肙苑茒葾蒝蒬薗蚖蜎蜵蝝蝯螈衏袁裫裷褑褤謜貟贠轅辕远逺遠邍邧酛鈨鋺鎱院願駌騵魭鳶鴛鵷鶢鶰鸢鸳鹓黿鼋鼘鼝𧻚𫘪', + 'Yue' => '㜧㜰㬦㰛㹊䆕䆢䋐䋤䖃䟑䟠䠯䡇䢁䢲䤦䥃䶳刖妜嬳岄岳嶽彟彠恱悅悦戉抈捳曰曱月樾瀹爚玥矱礿禴箹篗籆籥籰粤粵約约蘥蚎蚏越跀跃躍軏鈅鉞钺閱閲阅鸑鸙黦龠𥆟𩿠𫐄𬸚', + 'Yun' => '㚃㚺㛣㜏㞌㟦㩈䆬䇖䉙䚋䞫䢵䤞䨶䩵䪳䲰云伝傊允勻匀喗囩夽奫妘孕恽惲愠愪慍抎抣昀晕暈枟橒殒殞氲氳沄涢溳澐煴熅熉熨狁畇眃磒秐筠筼篔紜緷緼縕縜繧纭缊耘耺腪芸荺蒀蒕蒷蕓蕴薀藴蘊蝹褞賱贇赟运運郓郧鄆鄖酝醖醞鈗鋆阭陨隕雲霣韗韞韫韵韻頵餫馧馻齫齳𫖳', + 'Za' => '㞉㦫䕹䞙䨿䪞偺匝咂咋喒囋囐帀拶杂沞沯砸磼紥紮臜臢襍迊鉔雑雜雥韴魳𠯗', + 'Zai' => '㱰䏁䣬䮨䵧傤儎再哉在宰崽扗栽洅渽溨災灾烖甾睵縡菑賳載载酨𢦏𦞁', + 'Zan' => '㔆㜺㟛㣅㳫䍼䐶䬤䭕儧儹兂咱噆寁揝撍攅攒攢昝暂暫桚濽灒瓉瓒瓚禶簪簮糌襸讃讚賛贊赞趱趲蹔鄼酇錾鏨鐕鐟饡', + 'Zang' => '㘸㮜匨塟奘弉牂羘脏臓臟臧葬蔵賍賘贓贜赃銺駔驵髒', + 'Zao' => '㡟㯾㷮䖣䗢䜊䥣䲃傮凿唕唣喿噪慥早枣栆梍棗澡灶煰燥璪皁皂竃竈簉糟繰艁薻藻蚤譟趮蹧躁造遭醩鑿𡌣𢲵𥖨', + 'Ze' => '㖽㟙㣱㳁㳻㺓䇥䕉䕪䯔䰹䶦仄伬则則唶啧嘖夨嫧崱帻幘庂択择捑擇昃昗樍歵汄沢泎泽溭澤皟瞔矠礋笮箦簀舴蔶蠌襗諎謮責賾责赜迮鸅齚齰𦟜', + 'Zei' => '戝蠈賊贼鯽鰂鱡鲗', + 'Zen' => '㻸囎怎譖譛谮', + 'Zeng' => '㽪䎖䙢䰝増增憎橧熷璔甑矰磳繒缯罾譄贈赠鄫鋥锃鱛', + 'Zha' => '㗬㡸㦋㪥㱜㳐㴙㷢㾴䃎䄍䆛䋾䐒䕢䖳䛽䥷䮜䮢䱹䵙䶥乍偧劄厏吒咤哳喳奓宱扎抯拃挓揸搩搾摣札柞柤査栅楂榨樝渣溠灹炸煠牐甴痄皶皻眨砟箚耫苲蚱蚻觰詐譇譗诈踷醡鍘铡閘闸霅鮓鮺鲊鲝齄齇𠰏𥀈', + 'Zhai' => '㒀㡯㩟䍉䐱䔝债債夈宅寨捚摘斋斎榸檡瘵砦窄粂鉙齋𪘨', + 'Zhan' => '㔊㜊㞡㟞㠭㣶㮵㺘㻵䁪䁴䆄䋎䎒䗃䘺䟋䡀䦓䩅䩆䩇䪌䱠䱳䱼䶨佔偡占噡嫸展崭嶃嶄嶘嶦惉战戦戰搌斩斬旃旜枬栈栴桟棧榐橏毡氈氊沾湛琖盏盞瞻站粘綻绽菚薝蘸虥虦蛅覱詀詹譧譫讝谵趈輚輾轏邅醆閚霑颭飐飦饘驏驙魙鱣鳣鸇鹯黵𥇢𧂁𧮪𫗴', + 'Zhang' => '㙣㽴䛫丈仉仗傽墇嫜嶂帐帳幛幥张張彰慞扙掌暲杖樟涨涱漲漳獐璋痮瘬瘴瞕礃章粀粻胀脹蔁蟑賬账遧鄣鏱長长障餦騿鱆麞𤍤', + 'Zhao' => '㑿㕚㡽㷖㷹䃍䈃䈇䍜䍮䑲䝖䞴佋兆召啁垗妱巶找招旐昭曌枛棹櫂沼炤照燳爪爫狣瑵皽盄瞾窼笊罀罩羄肁肇肈詔诏赵趙釗鉊鍣钊駋鮡𠻥𦺓𬬿𬶐', + 'Zhe' => '㞏㡇㢎㪿㭙㭯㯙㯰㸙㸞䂞䇽䊞䎲䏳䐑䐲䓆䗪䜆䝃䝕䠦䩾䮰䵭乽厇哲啠啫喆嗻嚞埑嫬悊折摺晢晣柘樜歽浙淛潪着矺砓磔禇籷粍者著蔗虴蛰蜇蟄蟅袩褶襵詟謫謺讁讋谪赭輒輙轍辄辙这這遮銸锗馲鮿鷓鹧𠾀𡄡𧎴', + 'Zhen' => '㐱㓄㖘㘰㣀㪛㮳㯢㱽㲀㴨㼉䀕䂦䂧䃌䈯䊶䏖䑐䝩䟴䠴䨯䪴䪾䫬䲴䳲侦侲偵圳塦嫃寊屒帪弫抮挋振揕搸敶斟昣朕枕栕栚桢桭楨榛樼殝浈潧澵獉珍珎瑧瑱甄甽畛疹眕眞真眹砧碪祯禎禛稹箴籈紖紾絼縥纼缜聄胗臻萙葴蒖蓁薽袗裖診誫诊貞賑贞赈軫轃轸遉酖酙針鉁鋴錱鍼鎭鎮针镇阵陣震靕駗鬒鱵鴆鸩黰𣱽𥅘', + 'Zheng' => '㡠㡧㬹㱏㽀䂻䆸䇰䈣䋊䋫䍵䡕䥌䥭䦛䦶䱢争佂凧埩塣姃媜峥崝崢帧幀征徰徴徵怔愸抍拯挣掙掟揁撜政整晸正氶炡烝爭狰猙症癥眐睁睜筝箏篜糽聇蒸証諍證证诤踭郑鄭鉦錚钲铮鬇鯖鴊𢹑𦙫', + 'Zhi' => '㕄㗌㗧㘉㙷㛿㜱㜼㝂㡳㡶㣥㥀㨁㨖㩼㫑㮹㯄㲍㲛㴛㴯㸟㽻㿃䄺䅩䆈䇛䇧䉅䉜䎺䏯䐈䐭䑇䓋䓌䓜䓡䕌䘭䚦䚳䛗䝰䝷䞃䞠䟈䟡䡹䣽䤠䥍䦯䧴䩢䬹䭁䱃䱥䲀䳅䵂䵹之乿侄俧倁値值偫傂儨凪制劕劧卮厔只吱咫嗭址坁坧垁埴執墆墌夂妷姪娡嬂寘峙崻巵帋帙帜幟庢庤廌彘徏徔徝志忮怾恉慹憄懥懫戠执扺扻抧挃指挚掷搘搱摭摯擲擳支旘旨晊智枝枳柣栀栉桎梔梽植椥楖榰樴櫍櫛止殖汁汥汦沚治泜洔洷淔淽滍滞滯漐潌瀄炙熫犆狾猘瓆瓡畤疐疷疻痔痣直知砋礩祉祑祗祬禃禔秓秖秩秪秲秷稙稚稺穉窒筫紙紩絷綕緻縶織纸织置翐聀职職肢胑胝脂膣膱至致臸芖芝芷茋藢蘵蛭蜘螲蟙衹衼袟袠製襧覟觗觯觶訨誌豑豒豸貭質贄质贽趾跖跱踬踯蹠躑躓軄軹軽輊轵轾迣郅酯釞鉄銍鋕鑕铚锧阤阯陟隲隻雉馶馽駤騭騺驇骘鯯鳷鴙鴲鷙鸷黹鼅𡂒𡮞𦭜𬃊', + 'Zhong' => '㣫㲴㹣䇗䈺䝦䱰中仲伀众偅冢刣喠堹塚塜妐妕媑尰幒彸忠柊歱汷泈炂煄狆瘇盅眾祌种種穜筗籦終终肿腫舯茽蔠蚛螤螽衆衳衶衷諥踵蹱重鈡銿鍾鐘钟锺鴤鼨𧑆', + 'Zhou' => '㑇㑳㛩㤘㥮㨄㫶㼙㾭䈙䋓䎇䎻䑼䓟䖞䛆䧓䩜䶇伷侜僽冑周呪咒咮喌噣妯宙州帚徟掫昼晝晭洲淍炿烐珘甃疛皱皺盩睭矪箒籀籒籕粙粥紂縐纣绉肘胄舟荮菷葤詋詶謅譸诌诪賙赒軸輈輖轴辀週郮酎銂霌駎駲騆驟骤鯞鵃鸼𤏲𦂈', + 'Zhu' => '㑏㔉㝉㤖㦵㧣㫂㵭㶆㹥㺛㾻㿾䃴䇠䇡䇬䌵䍆䎷䐗䐢䕽䘄䘚䘢䝒䝬䟉䠱䡤䣷䥮䪒䬡䭖䮱䰞丶主伫佇住侏劚助劯嘱囑坾墸壴孎宔嵀拄斸曯朱杼柱株槠樦橥櫧櫫欘殶泏注洙渚潴濐瀦灟炢炷烛煑煮燭爥猪珠疰瘃眝瞩矚砫硃祝祩秼窋竚竹竺笁笜筑筯箸築篫紵紸絑纻罜羜翥舳苎茱茿莇蛀蛛蝫蠋蠩蠾袾註詝誅諸诛诸豬貯贮跓跦躅軴迬逐邾鉒銖鋳鑄钃铢铸陼霔馵駐駯驻鮢鯺鱁鴸麆麈鼄𡎺𣽆𤝹𬣞', + 'Zhua' => '抓檛簻膼髽', + 'Zhuai' => '拽跩', + 'Zhuan' => '䉵䏝䡱䧘专僎叀啭囀堟塼嫥孨専專撰灷瑑瑼甎砖磗磚竱篆篹籑腞膞蒃蟤襈諯譔賺赚転轉转鄟顓颛饌馔鱄𢐎', + 'Zhuang' => '壮壯壵妆妝娤庄庒戇撞桩梉樁湷漴焋状狀粧糚荘莊装裝𤶜', + 'Zhui' => '㗓㚝㩾㮅㾽䄌䨨䶆坠墜娷惴桘沝甀畷硾礈笍綴縋缀缒膇諈贅赘轛追醊錐錣鑆锥隹餟騅骓鵻', + 'Zhun' => '㡒准凖埻宒準稕窀綧肫衠訰諄谆迍𬘯', + 'Zhuo' => '㑁㒂㓸㣿㧳㧻㭬㹿㺟䂐䅵䆯䐁䓬䕴䟾䦃䪼䫎䮓䮕䶂丵倬劅卓叕啄啅圴妰娺彴拙捉撯擆擢斀斫斱斲斵晫桌梲棁棳椓槕櫡汋浊浞涿濁濯灂灼炪烵犳琸硺禚穛穱窡窧篧籗籱罬茁蠗蠿諁諑謶诼酌鋜鐯鐲镯鵫鷟𢽚𬸦', + 'Zi' => '㜽㞨㠿㧗㧘㰣㰷㱴㺭㽧㾅㿳䅆䅔䆅䎩䐉䔂䖪䘣䣎䦻䰵乲仔倳兹剚吇呰咨啙嗞姉姊姕姿子字孜孳孶崰嵫恣杍栥梓椔榟橴淄渍湽滋滓漬澬牸玆璾眥眦矷禌秄秭秶稵笫籽粢紎紫緇缁耔胏胔胾自芓茊茡茲荢葘蓻虸觜訾訿諮谘貲資赀资赼趑趦輜輺辎鄑釨鈭錙鍿鎡锱镃頾頿髭鯔鰦鲻鶅鼒齍龇𥬳𧂐𨩲', + 'Zong' => '㙡㚇㢔㣭㨑㯶㷓㹅䁓䈦䍟䑸䗥䙕䝋䰌倊倧偬傯堫宗嵏嵕嵸总惣惾愡捴揔搃摠昮朡棕椶潈熧燪猔猣疭瘲碂磫稯粽糉糭綜緃総緵縂縦縱總纵综翪腙葼蓗蝬豵踨踪蹤錝鍐鏓鑁騌騣骔鬃鬉鬷鯮鯼𠏭', + 'Zou' => '㔌㔿㵵㻓䠫奏揍棷棸楱箃緅菆諏诹走赱邹郰鄒鄹陬騶驺鯐鯫鲰黀齱齺𨽁', + 'Zu' => '㞺㰵㵀䔃䖕䚝䯿䱣俎傶卆卒哫唨崒崪族爼珇祖租箤組组葅蒩詛诅足踤踿鎺鏃镞阻靻𩺯', + 'Zuan' => '㸇䂎䌣䡽䤸䰖攥籫繤纂纉纘缵躜鑚鑽钻', + 'Zui' => '㝡㠑㭰㰎䘒䘹䮔厜嗺嘴噿嶊嶵晬最朘枠栬槜樶檇檌璻祽稡穝絊纗罪蕞蟕辠酔酻醉鋷錊', + 'Zun' => '䔿僔噂墫壿尊嶟捘撙樽繜罇譐遵銌鐏鱒鳟鶎鷷𠱜𨱔', + 'Zuo' => '㑅㘀㘴㝾㤰㭮㵶㸲䋏䎰䔘䝫䞢䞰䟶佐作侳做咗唑坐岝岞左座怍捽昨椊琢祚秨稓筰糳繓胙莋葃葄蓙袏鈼阼飵𠂇', +); diff --git a/wpslug.php b/wpslug.php new file mode 100644 index 0000000..168c26a --- /dev/null +++ b/wpslug.php @@ -0,0 +1,228 @@ +checkRequirements()) { + return; + } + + $this->loadDependencies(); + $this->loadTextdomain(); + $this->core = new WPSlug_Core(); + } + + private function checkRequirements() + { + if (version_compare(PHP_VERSION, "7.0", "<")) { + add_action('admin_notices', function() { + echo '

'; + echo esc_html__('WP Slug requires PHP 7.0 or higher. Please upgrade your PHP version.', 'wpslug'); + echo '

'; + }); + return false; + } + + if (version_compare(get_bloginfo("version"), "5.0", "<")) { + add_action('admin_notices', function() { + echo '

'; + echo esc_html__('WP Slug requires WordPress 5.0 or higher. Please upgrade your WordPress version.', 'wpslug'); + echo '

'; + }); + return false; + } + + return true; + } + + private function loadDependencies() + { + require_once WPSLUG_PLUGIN_DIR . "includes/class-wpslug-validator.php"; + require_once WPSLUG_PLUGIN_DIR . "includes/class-wpslug-settings.php"; + require_once WPSLUG_PLUGIN_DIR . "includes/class-wpslug-pinyin.php"; + require_once WPSLUG_PLUGIN_DIR . "includes/class-wpslug-optimizer.php"; + require_once WPSLUG_PLUGIN_DIR . "includes/class-wpslug-transliterator.php"; + require_once WPSLUG_PLUGIN_DIR . "includes/class-wpslug-translator.php"; + require_once WPSLUG_PLUGIN_DIR . "includes/class-wpslug-converter.php"; + require_once WPSLUG_PLUGIN_DIR . "includes/class-wpslug-core.php"; + + if (is_admin()) { + require_once WPSLUG_PLUGIN_DIR . "includes/class-wpslug-admin.php"; + } + } + + public function initLanguages() + { + $locale = apply_filters('plugin_locale', get_locale(), 'wpslug'); + $mo_file = WPSLUG_PLUGIN_DIR . "languages/wpslug-{$locale}.mo"; + + if (file_exists($mo_file)) { + load_textdomain('wpslug', $mo_file); + } + } + + public function loadTextdomain() + { + load_plugin_textdomain( + "wpslug", + false, + dirname(plugin_basename(__FILE__)) . "/languages/" + ); + } + + public function activate() + { + if (!function_exists("is_plugin_active")) { + require_once ABSPATH . "wp-admin/includes/plugin.php"; + } + + if (!$this->checkRequirements()) { + deactivate_plugins(plugin_basename(__FILE__)); + wp_die( + esc_html__('WP Slug plugin requirements not met. Please check your PHP and WordPress versions.', 'wpslug'), + esc_html__('Plugin Activation Error', 'wpslug'), + array('back_link' => true) + ); + } + + $this->loadDependencies(); + + try { + $settings = new WPSlug_Settings(); + $settings->createDefaultOptions(); + + $core = new WPSlug_Core(); + $core->activate(); + + add_option('wpslug_activation_redirect', true); + + } catch (Exception $e) { + error_log('WP Slug activation error: ' . $e->getMessage()); + wp_die( + esc_html__('An error occurred during plugin activation. Please check your server logs.', 'wpslug'), + esc_html__('Plugin Activation Error', 'wpslug'), + array('back_link' => true) + ); + } + } + + public function deactivate() + { + try { + if ($this->core) { + $this->core->deactivate(); + } + + delete_option('wpslug_activation_redirect'); + + } catch (Exception $e) { + error_log('WP Slug deactivation error: ' . $e->getMessage()); + } + } + + public static function uninstall() + { + try { + if (class_exists("WPSlug_Settings")) { + $settings = new WPSlug_Settings(); + $settings->uninstall(); + } + + delete_option('wpslug_activation_redirect'); + + } catch (Exception $e) { + error_log('WP Slug uninstall error: ' . $e->getMessage()); + } + } + + public function getCore() + { + return $this->core; + } + + public function getSettings() + { + if ($this->core) { + return $this->core->getSettings(); + } + return null; + } + + public function getConverter() + { + if ($this->core) { + return $this->core->getConverter(); + } + return null; + } + + public function getOptimizer() + { + if ($this->core) { + return $this->core->getOptimizer(); + } + return null; + } +} + +function wpslug() +{ + return WPSlug::getInstance(); +} + +if (is_admin()) { + add_action('admin_init', function() { + if (get_option('wpslug_activation_redirect', false)) { + delete_option('wpslug_activation_redirect'); + if (!isset($_GET['activate-multi'])) { + wp_safe_redirect(admin_url('options-general.php?page=wpslug')); + exit; + } + } + }); +} + +wpslug(); \ No newline at end of file