{"id":6294,"date":"2025-01-24T11:29:56","date_gmt":"2025-01-24T10:29:56","guid":{"rendered":"https:\/\/www.lrob.fr\/?p=6294"},"modified":"2025-06-26T12:28:46","modified_gmt":"2025-06-26T10:28:46","slug":"translate-an-entire-wordpress-site-in-one-go-with-translatepress","status":"publish","type":"post","link":"https:\/\/www.lrob.fr\/en\/blog\/news\/traduire-un-site-wordpress-entier-en-une-fois-avec-translatepress\/","title":{"rendered":"Translate a WordPress site - In one go with TranslatePress"},"content":{"rendered":"<p>Translating a WordPress site can be a challenge, especially when the automatic translation of a page requires it to be visited beforehand. As a<a href=\"https:\/\/www.lrob.fr\/en\/web-hosting\/\">WordPress hosting specialist<\/a> and <a href=\"https:\/\/www.lrob.fr\/en\/services\/wordpress-webmastering\/\">WordPress webmaster<\/a>I regularly work on multilingual sites with automatic translation. For this, I generally use TranslatePress Developer edition, with the DeepL API to perform the translation. The problem? Translating everything at once isn't natively possible. So we had to find a solution. Discover this solution and save hours!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Problem: It's not possible to translate the whole site at once.<\/h2>\n\n\n\n<p><strong>With TranslatePress, the translation of the content of your pages and articles, and above all their URLs (only available as a paid version), only takes place once someone has visited the page.<\/strong><\/p>\n\n\n\n<p>However, we'd like all URLs to be up to date, to avoid them changing for Google and generating 301 redirects, or even worse, 404 errors.<\/p>\n\n\n\n<p>On smaller sites, you can visit every page and article in every language.<\/p>\n\n\n\n<p><strong>For a site with hundreds of pages and articles, visiting them all by hand would take hours.<\/strong><\/p>\n\n\n\n<p>So how do you go about it?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Solution: Visit the entire sitemap automatically!<\/h2>\n\n\n\n<p>The solution is as follows: Create a script that visits all the pages on your site, based on its SiteMap.<\/p>\n\n\n\n<details class=\"wp-block-details is-layout-flow wp-block-details-is-layout-flow\"><summary>Your site doesn't have SiteMap? Click here for more details.<\/summary>\n<p>A SiteMap is a page, usually in XML format, that you can send to search engines (typically Google Search Console) to help them index all the pages on your site. This is quite essential with today's standards.<\/p>\n\n\n\n<p>If you don't already have a SiteMap, you can easily add one using, for example, the WordPress plugin <a href=\"https:\/\/wordpress.org\/plugins\/seo-by-rank-math\/\" target=\"_blank\" rel=\"noopener\">RankMath SEO<\/a>.<\/p>\n<\/details>\n\n\n\n<p>Then you need a terminal that supports BASH. On Linux and Mac, it's native. On Windows, it's possible that powershell supports BASH, but alternatively, I'd advise you to install <a href=\"https:\/\/learn.microsoft.com\/fr-fr\/windows\/wsl\/install\" target=\"_blank\" rel=\"noopener\">WSL<\/a>. If you have SSH access to a Linux server, this obviously works perfectly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The script<\/h2>\n\n\n\n<p>To save time, I used ChatGPT to create the following script. This will recursively visit all the URLs in your sitemap.xml via curl.<\/p>\n\n\n\n<p><em>You can call this script \"sitemap_visitor.sh\", for example, make it executable (chmod +x sitemap_visitor.sh), then run it with your sitemap.<\/em><\/p>\n\n\n\n<p>The two arguments to be indicated are :<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Your site URL<\/li>\n\n\n\n<li>Waiting time between each request (you can set this to 0 if you trust your server and your translation API consumption)<\/li>\n<\/ol>\n\n\n\n<p>For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.\/sitemap_visitor.sh https:\/\/wwww.votresite.fr\/sitemap_index.xml 1<\/code><\/pre>\n\n\n\n<p>Script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\nsitemap_url=\"$1\"\ndelay=\"$2\"\ndeclare -A visited_sitemaps  # Declare an associative array to track visited sitemaps\n\n# Function to visit all URLs in a sitemap\nvisit_sitemap_urls() {\n  local current_sitemap=\"$1\"\n\n  # Check if the sitemap has already been visited\n  if &#91;&#91; ${visited_sitemaps&#91;\"$current_sitemap\"]} ]]; then\n    echo \"Skipping already visited sitemap: $current_sitemap\"\n    return\n  fi\n\n  # Mark the current sitemap as visited\n  visited_sitemaps&#91;\"$current_sitemap\"]=1\n\n  # Fetch the sitemap\n  echo \"Fetching sitemap from: $current_sitemap\"\n  sitemap_content=$(curl -s -L \"$current_sitemap\")  # Added -L to follow redirects\n\n  if &#91;&#91; -z \"$sitemap_content\" ]]; then\n    echo \"Failed to fetch sitemap. Skipping.\"\n    return\n  fi\n\n  # Extract URLs from the sitemap using grep and sed\n  urls=$(echo \"$sitemap_content\" | grep -oP '(?&lt;=&lt;loc&gt;).*?(?=&lt;\/loc&gt;)')\n\n  if &#91;&#91; -z \"$urls\" ]]; then\n    echo \"No URLs found in the sitemap. Skipping.\"\n    return\n  fi\n\n  echo \"Found $(echo \"$urls\" | wc -l) URLs in the sitemap.\"\n\n  # Visit each URL\n  while read -r url; do\n    echo \"Visiting: $url\"\n    response_code=$(curl -o \/dev\/null -s -w \"%{http_code}\" -L \"$url\")  # Added -L here too\n\n    if &#91;&#91; \"$response_code\" == \"200\" ]]; then\n      echo \"Successfully visited: $url\"\n    else\n      echo \"Failed to visit $url: HTTP $response_code\"\n    fi\n\n    # Respectful crawling: wait between requests\n    sleep \"$delay\"\n\n    # Check if the URL is another sitemap\n    if &#91;&#91; \"$url\" == *.xml ]]; then\n      echo \"Found nested sitemap: $url\"\n      visit_sitemap_urls \"$url\"\n    fi\n  done &lt;&lt;&lt; \"$urls\"\n}\n\nvisit_sitemap_urls \"$sitemap_url\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">You've now translated your entire WordPress site!<\/h2>\n\n\n\n<p>I hope this tip saves you hours of work!<\/p>\n\n\n\n<div class=\"wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-6c531013 wp-block-group-is-layout-flex\">\n<p>For a site of around a hundred pages, and 5 additional languages, it cost me just under \u20ac20 for the DeepL API (+\u20ac4.99 subscription fee). Your experience may vary, so be sure to set limits, whether in TranslatePress or DeepL.<\/p>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69f4d0e9d7ec1&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"69f4d0e9d7ec1\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"829\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.lrob.fr\/wp-content\/uploads\/2025\/01\/translate-deepl-api-cost-1024x829.png\" alt=\"API cost DeepL\" class=\"wp-image-6295\" srcset=\"https:\/\/www.lrob.fr\/wp-content\/uploads\/2025\/01\/translate-deepl-api-cost-1024x829.png 1024w, https:\/\/www.lrob.fr\/wp-content\/uploads\/2025\/01\/translate-deepl-api-cost-300x243.png 300w, https:\/\/www.lrob.fr\/wp-content\/uploads\/2025\/01\/translate-deepl-api-cost-150x121.png 150w, https:\/\/www.lrob.fr\/wp-content\/uploads\/2025\/01\/translate-deepl-api-cost.png 1468w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n<\/div>\n\n\n\n<p><em>PS: This solution also allows you to cache your entire site after a site dump. \ud83d\ude1c<\/em><\/p>\n\n\n\n<div class=\"wp-block-group is-layout-flex wp-block-group-is-layout-flex\">\n<p><strong>Already an LRob customer and want to translate your site?<\/strong><\/p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/portail.lrob.fr\/produit\/gestion-annuelle-translatepress\/\" target=\"_blank\" rel=\"noopener\">Get TranslatePress<\/a><\/div>\n<\/div>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-text-color has-custom-darker-blue-color has-alpha-channel-opacity has-custom-darker-blue-background-color has-background is-style-default\" style=\"margin-top:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--30)\"\/>\n\n\n\n<p class=\"is-style-text-subtitle is-style-text-subtitle--1\"><strong>Looking for a <a href=\"https:\/\/www.lrob.fr\/en\/web-hosting\/\">competent and committed WordPress host<\/a> ?<\/strong><br><strong>Or a <a href=\"https:\/\/www.lrob.fr\/en\/services\/wordpress-webmastering\/\">Webmaster<\/a> ?<\/strong><\/p>\n\n\n\n<div class=\"wp-block-group is-layout-flex wp-block-group-is-layout-flex\">\n<p class=\"is-style-text-subtitle is-style-text-subtitle--2\">Choose LRob!<\/p>\n\n\n\n<div class=\"wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-a89b3969 wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/www.lrob.fr\/en\/web-hosting\/\">WordPress web hosting<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/www.lrob.fr\/en\/services\/wordpress-webmastering\/\">WordPress webmaster<\/a><\/div>\n<\/div>\n<\/div>\n\n\n\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>Traduire un site WordPress peut \u00eatre un challenge, en particulier lorsque la traduction automatique d&rsquo;une page n\u00e9cessite sa visite au pr\u00e9alable. En tant qu&rsquo;h\u00e9bergeur sp\u00e9cialiste WordPress et webmaster sp\u00e9cialiste WordPress, j&rsquo;interviens r\u00e9guli\u00e8rement sur des sites multilingues avec traduction automatique. Pour cela, j&rsquo;utilise g\u00e9n\u00e9ralement TranslatePress Developer edition, avec l&rsquo;API DeepL pour op\u00e9rer cette traduction. Le probl\u00e8me [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":6295,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-6294","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news"],"_links":{"self":[{"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/posts\/6294","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/comments?post=6294"}],"version-history":[{"count":8,"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/posts\/6294\/revisions"}],"predecessor-version":[{"id":7534,"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/posts\/6294\/revisions\/7534"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/media\/6295"}],"wp:attachment":[{"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/media?parent=6294"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/categories?post=6294"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lrob.fr\/en\/wp-json\/wp\/v2\/tags?post=6294"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}