{"data":{"site":{"siteMetadata":{"title":"Lime Brains","description":"We are The Software House where business questions meet software answers.","url":"https://limebrains.com"}},"markdownRemark":{"html":"<h1>Problem 😱</h1>\n<p>You want to share your translation files to translation team.</p>\n<p>Possible solutions:</p>\n<ol>\n<li>locize</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">+ easy to use\n+ integration with google translate\n\n- monthly subscription + usage price </code></pre></div>\n<ol start=\"2\">\n<li>zanata</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">+ easy to use\n+ has cli\n\n- bad ui\n- no longer supports new projects, need to be selfhosted</code></pre></div>\n<ol start=\"3\">\n<li>send them xlsx / pot files</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">+ easy to integrate\n+ free\n\n- hard to maintain\n- merge conflicts\n- non versioned</code></pre></div>\n<hr>\n<h1>Solution 🤓</h1>\n<h2>🎉 🎉 🎉 use google sheets 🎉 🎉 🎉</h2>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">+ easy to use\n+ versioned\n+ free\n+ has google translate feature\n\n- google might lower limits on free API calls</code></pre></div>\n<p>Result:</p>\n<p><img src=\"https://i.imgur.com/xRnFwmd.png\" alt=\"Result\"></p>\n<p>Flow:</p>\n<ol>\n<li>use your i18n scanner to extract keys into json <code class=\"language-text\">{key: \"\"}</code> name of file</li>\n</ol>\n<p>i18next-parser.config.js</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">createOldCatalogs</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// save previous translation catalogs to the \\_old folder</span>\n\n  <span class=\"token literal-property property\">lexers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">js</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'JsxLexer'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">jsx</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'JsxLexer'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'JsxLexer'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token literal-property property\">locales</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'en'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token comment\">// An array of the locales in your applications</span>\n\n  <span class=\"token literal-property property\">namespaceSeparator</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">keySeparator</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n  <span class=\"token comment\">// Namespace separator used in your translation keys</span>\n  <span class=\"token comment\">// If you want to use plain english keys, separators such as `.` and `:` </span>\n  <span class=\"token comment\">// will conflict. You might want to set `keySeparator: false` and </span>\n  <span class=\"token comment\">// `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.</span>\n\n  <span class=\"token comment\">// output: 'i18n/$LOCALE/$NAMESPACE.json',</span>\n  <span class=\"token literal-property property\">output</span><span class=\"token operator\">:</span> <span class=\"token string\">'public/locales/$LOCALE.json'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token comment\">// Supports $LOCALE and $NAMESPACE injection</span>\n  <span class=\"token comment\">// Supports JSON (.json) and YAML (.yml) file formats</span>\n  <span class=\"token comment\">// Where to write the locale files relative to process.cwd()</span>\n\n  <span class=\"token literal-property property\">input</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token string\">'src/**/**/*.js'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'src/**/**/*.jsx'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token comment\">// An array of globs that describe where to look for source files</span>\n  <span class=\"token comment\">// relative to the location of the configuration file</span>\n  <span class=\"token comment\">// Globs syntax: https://github.com/isaacs/node-glob#glob-primer</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<ol start=\"2\">\n<li>sync files with google sheets</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"shell\"><pre class=\"language-shell\"><code class=\"language-shell\">pip <span class=\"token function\">install</span> <span class=\"token assign-left variable\">gspread</span><span class=\"token operator\">==</span><span class=\"token number\">3.6</span>.0\npython i18n_google_sheets.py</code></pre></div>\n<p>i18n<em>google</em>sheets.py</p>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> os\n<span class=\"token keyword\">import</span> json\n<span class=\"token keyword\">from</span> collections <span class=\"token keyword\">import</span> defaultdict\n<span class=\"token keyword\">from</span> pathlib <span class=\"token keyword\">import</span> Path\n\n<span class=\"token keyword\">import</span> gspread\n\ncurr_dir <span class=\"token operator\">=</span> Path<span class=\"token punctuation\">(</span>__file__<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>parent\nroot_dir <span class=\"token operator\">=</span> curr_dir\nservice_account_path <span class=\"token operator\">=</span> root_dir <span class=\"token operator\">/</span> <span class=\"token string\">'your_app_google_credentials.json'</span>\nsheet_id <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'SHEET_ID'</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">or</span> <span class=\"token string\">'sheet_id'</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">get_worksheet</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    gc <span class=\"token operator\">=</span> gspread<span class=\"token punctuation\">.</span>service_account<span class=\"token punctuation\">(</span>\n        filename<span class=\"token operator\">=</span>service_account_path<span class=\"token punctuation\">.</span>absolute<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>as_posix<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">)</span>\n\n    sheet <span class=\"token operator\">=</span> gc<span class=\"token punctuation\">.</span>open_by_key<span class=\"token punctuation\">(</span>sheet_id<span class=\"token punctuation\">)</span>\n    worksheet <span class=\"token operator\">=</span> sheet<span class=\"token punctuation\">.</span>get_worksheet<span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> worksheet\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">add_missing_keys</span><span class=\"token punctuation\">(</span>worksheet<span class=\"token punctuation\">,</span> expected_keys<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    records <span class=\"token operator\">=</span> worksheet<span class=\"token punctuation\">.</span>get_all_records<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string-interpolation\"><span class=\"token string\">f\"from google </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>records<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span><span class=\"token punctuation\">)</span>\n    missing_keys <span class=\"token operator\">=</span> <span class=\"token builtin\">set</span><span class=\"token punctuation\">(</span>expected_keys<span class=\"token punctuation\">)</span>\n\n    last_idx <span class=\"token operator\">=</span> <span class=\"token number\">0</span>\n    <span class=\"token keyword\">for</span> row_idx<span class=\"token punctuation\">,</span> row <span class=\"token keyword\">in</span> <span class=\"token builtin\">enumerate</span><span class=\"token punctuation\">(</span>records<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        key <span class=\"token operator\">=</span> row<span class=\"token punctuation\">.</span>pop<span class=\"token punctuation\">(</span><span class=\"token string\">'key'</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n            missing_keys<span class=\"token punctuation\">.</span>remove<span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">except</span> KeyError<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string-interpolation\"><span class=\"token string\">f\"consider removing key in gsheets which was not expected, key=</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>key<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span><span class=\"token punctuation\">)</span>\n        last_idx <span class=\"token operator\">=</span> row_idx <span class=\"token operator\">+</span> <span class=\"token number\">1</span>\n\n    worksheet<span class=\"token punctuation\">.</span>insert_rows<span class=\"token punctuation\">(</span>\n        <span class=\"token punctuation\">[</span><span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token keyword\">for</span> key <span class=\"token keyword\">in</span> missing_keys<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        row<span class=\"token operator\">=</span>last_idx <span class=\"token operator\">+</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">get_expected_keys</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    en_file_path <span class=\"token operator\">=</span> root_dir <span class=\"token operator\">/</span> <span class=\"token string\">'public'</span> <span class=\"token operator\">/</span> <span class=\"token string\">'locales'</span> <span class=\"token operator\">/</span> <span class=\"token string\">'en.json'</span>\n    <span class=\"token keyword\">with</span> <span class=\"token builtin\">open</span><span class=\"token punctuation\">(</span>en_file_path<span class=\"token punctuation\">,</span> <span class=\"token string\">'r'</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> en_file<span class=\"token punctuation\">:</span>\n        keys <span class=\"token operator\">=</span> json<span class=\"token punctuation\">.</span>load<span class=\"token punctuation\">(</span>en_file<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>keys<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token builtin\">list</span><span class=\"token punctuation\">(</span>keys<span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">pull</span><span class=\"token punctuation\">(</span>worksheet<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    records <span class=\"token operator\">=</span> worksheet<span class=\"token punctuation\">.</span>get_all_records<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    languages <span class=\"token operator\">=</span> defaultdict<span class=\"token punctuation\">(</span><span class=\"token builtin\">dict</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">for</span> row <span class=\"token keyword\">in</span> records<span class=\"token punctuation\">:</span>\n        key <span class=\"token operator\">=</span> row<span class=\"token punctuation\">.</span>pop<span class=\"token punctuation\">(</span><span class=\"token string\">'key'</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">for</span> lang<span class=\"token punctuation\">,</span> value <span class=\"token keyword\">in</span> row<span class=\"token punctuation\">.</span>items<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n            languages<span class=\"token punctuation\">[</span>lang<span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> value\n\n    <span class=\"token keyword\">return</span> languages\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">save</span><span class=\"token punctuation\">(</span>languages<span class=\"token punctuation\">:</span> <span class=\"token builtin\">dict</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">for</span> lng<span class=\"token punctuation\">,</span> translations <span class=\"token keyword\">in</span> languages<span class=\"token punctuation\">.</span>items<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        file_path <span class=\"token operator\">=</span> root_dir <span class=\"token operator\">/</span> <span class=\"token string\">'public'</span> <span class=\"token operator\">/</span> <span class=\"token string\">'locales'</span> <span class=\"token operator\">/</span> <span class=\"token string-interpolation\"><span class=\"token string\">f'</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>lng<span class=\"token punctuation\">}</span></span><span class=\"token string\">.json'</span></span>\n        <span class=\"token keyword\">with</span> <span class=\"token builtin\">open</span><span class=\"token punctuation\">(</span>file_path<span class=\"token punctuation\">,</span> <span class=\"token string\">'w'</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> <span class=\"token builtin\">file</span><span class=\"token punctuation\">:</span>\n            json<span class=\"token punctuation\">.</span>dump<span class=\"token punctuation\">(</span>translations<span class=\"token punctuation\">,</span> <span class=\"token builtin\">file</span><span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">sync</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span><span class=\"token operator\">></span> <span class=\"token builtin\">dict</span><span class=\"token punctuation\">:</span>\n    keys <span class=\"token operator\">=</span> get_expected_keys<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n    worksheet <span class=\"token operator\">=</span> get_worksheet<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    add_missing_keys<span class=\"token punctuation\">(</span>worksheet<span class=\"token operator\">=</span>worksheet<span class=\"token punctuation\">,</span> expected_keys<span class=\"token operator\">=</span>keys<span class=\"token punctuation\">)</span>\n    languages <span class=\"token operator\">=</span> pull<span class=\"token punctuation\">(</span>worksheet<span class=\"token operator\">=</span>worksheet<span class=\"token punctuation\">)</span>\n    save<span class=\"token punctuation\">(</span>languages<span class=\"token operator\">=</span>languages<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> languages\n\n\n<span class=\"token keyword\">if</span> __name__ <span class=\"token operator\">==</span> <span class=\"token string\">'__main__'</span><span class=\"token punctuation\">:</span>\n    languages <span class=\"token operator\">=</span> sync<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">for</span> lng<span class=\"token punctuation\">,</span> values <span class=\"token keyword\">in</span> languages<span class=\"token punctuation\">.</span>items<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string-interpolation\"><span class=\"token string\">f\"\\nlanguage: </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>lng<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string-interpolation\"><span class=\"token string\">f\"\\n\\n</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>values<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span><span class=\"token punctuation\">)</span></code></pre></div>","excerpt":"Problem 😱 You want to share your translation files to translation team. Possible solutions: locize zanata send them xlsx / pot files…","frontmatter":{"title":"Create i18n backend using google sheets with google translate.","subtitle":"Create i18n backend using google sheets with google translate.","date":"2021-03-02 13:30","seo":{"title":"Create i18n backend using google sheets with google translate.","description":"Create i18n backend using google sheets with google translate.","noindex":false}},"fields":{"slug":"/blog/2021-03-02T13:30-google-sheets-with-google-translate-backend-for-i18next/"}}},"pageContext":{"slug":"/blog/2021-03-02T13:30-google-sheets-with-google-translate-backend-for-i18next/","indexable":false}}