CINXE.COM
Translation — Nextcloud latest Developer Manual latest documentation
<!DOCTYPE html> <html class="writer-html5" lang="en" data-content_root="../../"> <head> <meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Translation — Nextcloud latest Developer Manual latest documentation</title> <link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=fa44fd50" /> <link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=e59714d7" /> <link rel="stylesheet" type="text/css" href="../../_static/copybutton.css?v=76b2166b" /> <link rel="stylesheet" type="text/css" href="../../_static/custom.css?v=bad88653" /> <link rel="stylesheet" type="text/css" href="../../_static/dark_mode_css/general.css?v=c0a7eb24" /> <link rel="stylesheet" type="text/css" href="../../_static/dark_mode_css/dark.css?v=70edf1c7" /> <script src="../../_static/jquery.js?v=5d32c60e"></script> <script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script> <script src="../../_static/documentation_options.js?v=f4332903"></script> <script src="../../_static/doctools.js?v=9bcbadda"></script> <script src="../../_static/sphinx_highlight.js?v=dc90522c"></script> <script src="../../_static/clipboard.min.js?v=a7894cd8"></script> <script src="../../_static/copybutton.js?v=f281be69"></script> <script src="../../_static/dark_mode_js/default_light.js?v=c2e647ce"></script> <script src="../../_static/dark_mode_js/theme_switcher.js?v=358d3910"></script> <script src="../../_static/js/theme.js"></script> <link rel="index" title="Index" href="../../genindex.html" /> <link rel="search" title="Search" href="../../search.html" /> <link rel="next" title="Theming support" href="theming.html" /> <link rel="prev" title="CSS" href="css.html" /> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search" > <a href="../../index.html"> <img src="../../_static/logo-white.png" class="logo" alt="Logo"/> </a> <div role="search"> <form id="rtd-search-form" class="wy-form" action="../../search.html" method="get"> <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="../../prologue/index.html">Prologue</a></li> <li class="toctree-l1"><a class="reference internal" href="../../getting_started/index.html">Getting started</a></li> <li class="toctree-l1 current"><a class="reference internal" href="../index.html">Basic concepts</a><ul class="current"> <li class="toctree-l2"><a class="reference internal" href="../request_lifecycle.html">Request lifecycle</a></li> <li class="toctree-l2"><a class="reference internal" href="../routing.html">Routing</a></li> <li class="toctree-l2"><a class="reference internal" href="../dependency_injection.html">Dependency injection</a></li> <li class="toctree-l2"><a class="reference internal" href="../controllers.html">Controllers</a></li> <li class="toctree-l2"><a class="reference internal" href="../middlewares.html">Middlewares</a></li> <li class="toctree-l2"><a class="reference internal" href="../events.html">Events</a></li> <li class="toctree-l2 current"><a class="reference internal" href="index.html">Front-end</a><ul class="current"> <li class="toctree-l3"><a class="reference internal" href="templates.html">Templates</a></li> <li class="toctree-l3"><a class="reference internal" href="js.html">JavaScript</a></li> <li class="toctree-l3"><a class="reference internal" href="css.html">CSS</a></li> <li class="toctree-l3 current"><a class="current reference internal" href="#">Translation</a><ul> <li class="toctree-l4"><a class="reference internal" href="#php">PHP</a></li> <li class="toctree-l4"><a class="reference internal" href="#templates">Templates</a></li> <li class="toctree-l4"><a class="reference internal" href="#javascript">JavaScript</a></li> <li class="toctree-l4"><a class="reference internal" href="#important-notes">Important notes</a></li> <li class="toctree-l4"><a class="reference internal" href="#adding-translations">Adding translations</a></li> </ul> </li> <li class="toctree-l3"><a class="reference internal" href="theming.html">Theming support</a></li> </ul> </li> <li class="toctree-l2"><a class="reference internal" href="../backgroundjobs.html">Background jobs (Cron)</a></li> <li class="toctree-l2"><a class="reference internal" href="../caching.html">Caching</a></li> <li class="toctree-l2"><a class="reference internal" href="../logging.html">Logging</a></li> <li class="toctree-l2"><a class="reference internal" href="../setting.html">Settings</a></li> <li class="toctree-l2"><a class="reference internal" href="../storage/index.html">Storage and database</a></li> <li class="toctree-l2"><a class="reference internal" href="../public_share_template.html">Public share template</a></li> <li class="toctree-l2"><a class="reference internal" href="../testing.html">Testing</a></li> </ul> </li> <li class="toctree-l1"><a class="reference internal" href="../../app_development/index.html">App development</a></li> <li class="toctree-l1"><a class="reference internal" href="../../server/index.html">Server development</a></li> <li class="toctree-l1"><a class="reference internal" href="../../digging_deeper/index.html">Digging deeper</a></li> <li class="toctree-l1"><a class="reference internal" href="../../app_publishing_maintenance/index.html">App publishing and maintenance</a></li> <li class="toctree-l1"><a class="reference internal" href="../../design/index.html">Interface & interaction design</a></li> <li class="toctree-l1"><a class="reference internal" href="../../html_css_design/index.html">HTML/CSS guidelines</a></li> <li class="toctree-l1"><a class="reference internal" href="../../client_apis/index.html">Clients and Client APIs</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="../../index.html">Nextcloud latest Developer Manual</a> </nav> <div class="wy-nav-content"> <div class="rst-content style-external-links"> <div role="navigation" aria-label="Page navigation"> <ul class="wy-breadcrumbs"> <li><a href="../../index.html" class="icon icon-home" aria-label="Home"></a></li> <li class="breadcrumb-item"><a href="../index.html">Basic concepts</a></li> <li class="breadcrumb-item"><a href="index.html">Front-end</a></li> <li class="breadcrumb-item active">Translation</li> <li class="wy-breadcrumbs-aside"> <a href="https://github.com/nextcloud/documentation/edit/master/developer_manual/basics/front-end/l10n.rst" class="fa fa-github"> Edit on GitHub</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <section id="translation"> <h1>Translation<a class="headerlink" href="#translation" title="Link to this heading"></a></h1> <p>Nextcloud provides mechanisms for internationalization (make an application translatable) and localization (add translations for specific languages). This section provides detailed instructions for both aspects. In order to make your app translatable (internationalization), you should use Nextcloud’s methods for translating strings. They are available for both the server-side (PHP, Templates) as well as for the client-side (JavaScript).</p> <section id="php"> <h2>PHP<a class="headerlink" href="#php" title="Link to this heading"></a></h2> <p>If localized strings are used in the backend code, simply inject the <code class="docutils literal notranslate"><span class="pre">\OCP\IL10N</span></code> class into your service via type hinting it in the constructor. You will automatically get the language object containing the translations of your app:</p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><?</span><span class="nx">php</span> <span class="k">namespace</span> <span class="nx">OCA\MyApp\Service</span><span class="p">;</span> <span class="k">use</span> <span class="nx">OCP\IL10N</span><span class="p">;</span> <span class="k">class</span> <span class="nc">AuthorService</span> <span class="p">{</span> <span class="sd">/** @var IL10N */</span> <span class="k">private</span> <span class="nv">$l</span><span class="p">;</span> <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">IL10N</span> <span class="nv">$l</span><span class="p">)</span> <span class="p">{</span> <span class="nv">$this</span><span class="o">-></span><span class="na">l</span> <span class="o">=</span> <span class="nv">$l</span><span class="p">;</span> <span class="p">}</span> <span class="nx">…</span> <span class="p">}</span> </pre></div> </div> <p>Strings can then be translated in the following way:</p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><?</span><span class="nx">php</span> <span class="nx">…</span> <span class="k">class</span> <span class="nc">AuthorService</span> <span class="p">{</span> <span class="nx">…</span> <span class="k">public</span> <span class="k">function</span> <span class="nf">getLanguageCode</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">l</span><span class="o">-></span><span class="na">getLanguageCode</span><span class="p">();</span> <span class="p">}</span> <span class="k">public</span> <span class="nx">sayHello</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// Simple string</span> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Hello'</span><span class="p">);</span> <span class="p">}</span> <span class="k">public</span> <span class="k">function</span> <span class="nf">getAuthorName</span><span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// String using a parameter</span> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Getting author %1$s'</span><span class="p">,</span> <span class="p">[</span><span class="nv">$name</span><span class="p">]);</span> <span class="p">}</span> <span class="k">public</span> <span class="k">function</span> <span class="nf">getAuthors</span><span class="p">(</span><span class="nv">$count</span><span class="p">,</span> <span class="nv">$city</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Translation with plural</span> <span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="na">l</span><span class="o">-></span><span class="na">n</span><span class="p">(</span> <span class="s1">'%n author is currently in the city %1$s'</span><span class="p">,</span> <span class="c1">// singular string</span> <span class="s1">'%n authors are currently in the city %1$s'</span><span class="p">,</span> <span class="c1">// plural string</span> <span class="nv">$count</span><span class="p">,</span> <span class="c1">// number to decide which plural to use</span> <span class="p">[</span><span class="nv">$city</span><span class="p">]</span> <span class="c1">// further parameters are possible</span> <span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </pre></div> </div> <section id="correct-plurals"> <h3>Correct plurals<a class="headerlink" href="#correct-plurals" title="Link to this heading"></a></h3> <p>If you use a plural, you <strong>must</strong> also use the <code class="docutils literal notranslate"><span class="pre">%n</span></code> placeholder. The placeholder defines the plural and the word without the number preceding is wrong. If you don’t know/have a number for your translation, e.g. because you don’t know how many items are going to be selected, just use an undefined plural. They exist in every language and have one form. They do not follow the normal plural pattern.</p> <p>Example:</p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><?</span><span class="nx">php</span> <span class="c1">// BAD: Plural without count</span> <span class="nv">$title</span> <span class="o">=</span> <span class="nv">$l</span><span class="o">-></span><span class="na">n</span><span class="p">(</span><span class="s1">'Import calendar'</span><span class="p">,</span> <span class="s1">'Import calendars'</span><span class="p">,</span> <span class="nv">$selectionLength</span><span class="p">)</span> <span class="c1">// BETTER: Plural has count, but disrupting to read and unnecessary information</span> <span class="nv">$title</span> <span class="o">=</span> <span class="nv">$l</span><span class="o">-></span><span class="na">n</span><span class="p">(</span><span class="s1">'Import %n calendar'</span><span class="p">,</span> <span class="s1">'Import %n calendars'</span><span class="p">,</span> <span class="nv">$selectionLength</span><span class="p">)</span> <span class="c1">// BEST: Simple string with undefined plural</span> <span class="nv">$title</span> <span class="o">=</span> <span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Import calendars'</span><span class="p">)</span> </pre></div> </div> </section> <section id="language-of-other-users"> <h3>Language of other users<a class="headerlink" href="#language-of-other-users" title="Link to this heading"></a></h3> <p>If you need to get the language of another user, e.g. to send them an email or inside a background job, there are also the <code class="docutils literal notranslate"><span class="pre">force_language</span></code> and <code class="docutils literal notranslate"><span class="pre">default_language</span></code> configuration options to consider. To make this easier, the <code class="docutils literal notranslate"><span class="pre">OCP\L10N\IFactory</span></code> class comes with a <code class="docutils literal notranslate"><span class="pre">getUserLanguage</span></code> method:</p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><?</span><span class="nx">php</span> <span class="k">use</span> <span class="nx">OCP\L10N\IFactory</span><span class="p">;</span> <span class="k">class</span> <span class="nc">SendEmail</span> <span class="p">{</span> <span class="sd">/** @var IFactory */</span> <span class="k">private</span> <span class="nv">$l10nFactory</span><span class="p">;</span> <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">IFactory</span> <span class="nv">$l10nFactory</span><span class="p">)</span> <span class="p">{</span> <span class="nv">$this</span><span class="o">-></span><span class="na">l10nFactory</span> <span class="o">=</span> <span class="nv">$l10nFactory</span><span class="p">;</span> <span class="p">}</span> <span class="k">public</span> <span class="k">function</span> <span class="nf">send</span><span class="p">(</span><span class="nx">IUser</span> <span class="nv">$user</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span> <span class="nv">$lang</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="na">l10nFactory</span><span class="o">-></span><span class="na">getUserLanguage</span><span class="p">(</span><span class="nv">$user</span><span class="p">);</span> <span class="nv">$l</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="na">l10nFactory</span><span class="o">-></span><span class="na">get</span><span class="p">(</span><span class="s1">'myapp'</span><span class="p">,</span> <span class="nv">$lang</span><span class="p">);</span> <span class="c1">// …</span> <span class="p">}</span> </pre></div> </div> </section> </section> <section id="templates"> <h2>Templates<a class="headerlink" href="#templates" title="Link to this heading"></a></h2> <p>In every template the global variable <strong>$l</strong> can be used to translate the strings using its methods <strong>t()</strong> and <strong>n()</strong>:</p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="nx">div</span><span class="o">><?</span><span class="nx">php</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Showing %$1s files'</span><span class="p">,</span> <span class="nv">$_</span><span class="p">[</span><span class="s1">'count'</span><span class="p">]));</span> <span class="cp">?></span><span class="x"></div></span> <span class="x"><button></span><span class="cp"><?php</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Hide'</span><span class="p">));</span> <span class="cp">?></span><span class="x"></button></span> </pre></div> </div> <p>For the right date format use <code class="docutils literal notranslate"><span class="pre"><?php</span> <span class="pre">p($l->l('date',</span> <span class="pre">time()));?></span></code>.</p> </section> <section id="javascript"> <h2>JavaScript<a class="headerlink" href="#javascript" title="Link to this heading"></a></h2> <p>There are global functions <strong>t()</strong> and <strong>n()</strong> available for translating strings in javascript code. They differ a bit in terms of usage compared to php:</p> <ul class="simple"> <li><p>First argument is the appId e.g. <code class="docutils literal notranslate"><span class="pre">'myapp'</span></code></p></li> <li><p>Placeholders (apart from the count in plurals) use single-mustache brackets with meaning-full descriptors.</p></li> <li><p>The parameter list is an object with the descriptors as key.</p></li> </ul> <div class="highlight-js notranslate"><div class="highlight"><pre><span></span><span class="nx">t</span><span class="p">(</span><span class="s1">'myapp'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Hello World!'</span><span class="p">);</span> <span class="nx">t</span><span class="p">(</span><span class="s1">'myapp'</span><span class="p">,</span><span class="w"> </span><span class="s1">'{name} is available. Get {linkstart}more information{linkend}'</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="s1">'Nextcloud 16'</span><span class="p">,</span><span class="w"> </span><span class="nx">linkstart</span><span class="o">:</span><span class="w"> </span><span class="s1">'<a href="...">'</span><span class="p">,</span><span class="w"> </span><span class="nx">linkend</span><span class="o">:</span><span class="w"> </span><span class="s1">'</a>'</span><span class="p">});</span> <span class="nx">n</span><span class="p">(</span><span class="s1">'myapp'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Import %n calendar into {collection}'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Import %n calendars into {collection}'</span><span class="p">,</span><span class="w"> </span><span class="nx">selectionLength</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="nx">collection</span><span class="o">:</span><span class="w"> </span><span class="s1">'Nextcloud'</span><span class="p">});</span> </pre></div> </div> </section> <section id="important-notes"> <h2>Important notes<a class="headerlink" href="#important-notes" title="Link to this heading"></a></h2> <p>Please also look through the following steps to improve your strings and make them better translatable by others</p> <section id="improving-your-translations"> <h3>Improving your translations<a class="headerlink" href="#improving-your-translations" title="Link to this heading"></a></h3> <p>You shall <strong>never split</strong> sentences and <strong>never concatenate</strong> two translations (e.g. “Enable” and “dark mode” can not be combined to “Enable dark mode”, because languages might have to use different cases)! Translators lose the context and they have no chance to possibly re-arrange words/parts as needed.</p> <p>Bad example:</p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><?</span><span class="nx">php</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Select file from'</span><span class="p">))</span> <span class="o">.</span> <span class="s1">' '</span><span class="p">;</span> <span class="cp">?></span><span class="x"><a href='#' id="browselink"></span><span class="cp"><?php</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'local filesystem'</span><span class="p">));</span><span class="cp">?></span><span class="x"></a></span><span class="cp"><?php</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">' or '</span><span class="p">));</span> <span class="cp">?></span><span class="x"><a href='#' id="cloudlink"></span><span class="cp"><?php</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'cloud'</span><span class="p">));</span><span class="cp">?></span><span class="x"></a></span> </pre></div> </div> <p>Translators will translate:</p> <ul class="simple"> <li><p>Select file from</p></li> <li><p>local filesystem</p></li> <li><p>‘ or ‘</p></li> <li><p>cloud</p></li> </ul> <p>Translating these individual strings results in <code class="docutils literal notranslate"><span class="pre">local</span> <span class="pre">filesystem</span></code> and <code class="docutils literal notranslate"><span class="pre">cloud</span></code> losing case. The two white spaces surrounding <code class="docutils literal notranslate"><span class="pre">or</span></code> will get lost while translating as well. For languages that have a different grammatical order it prevents the translators from reordering the sentence components.</p> <p>So the following code is a bit better, but suffers from another issue:</p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><?</span><span class="nx">php</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Select file from <a href="#" id="browselink">local filesystem</a> or <a href="#" id="cloudlink">cloud</a>'</span><span class="p">));</span><span class="cp">?></span> </pre></div> </div> <p>In this case the translators can re-arrange as they like, but have to deal with your markup and can mess it up easily. It is better to <strong>keep the markup out</strong> of your code, so the following translation is even better:</p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><?</span><span class="nx">php</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Select file from %slocal filesystem%s or %scloud%s'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'<a href="#" id="browselink">'</span><span class="p">,</span> <span class="s1">'</a>'</span><span class="p">,</span> <span class="s1">'<a href="#" id="cloudlink">'</span><span class="p">,</span> <span class="s1">'</a>'</span><span class="p">]));</span><span class="cp">?></span> </pre></div> </div> <p>But there is one last problem with this. In case the language has to turn things around, your code will still insert the parameters in the given order and they can not re-order them. To prevent this last hurdle simply <strong>use positioned placeholders</strong> like <code class="docutils literal notranslate"><span class="pre">%1$s</span></code>:</p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><?</span><span class="nx">php</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Select file from %1$slocal filesystem%2$s or %3$scloud%4$s'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'<a href="#" id="browselink">'</span><span class="p">,</span> <span class="s1">'</a>'</span><span class="p">,</span> <span class="s1">'<a href="#" id="cloudlink">'</span><span class="p">,</span> <span class="s1">'</a>'</span><span class="p">]));</span><span class="cp">?></span> </pre></div> </div> <p>This allows translators to have the cloudlink before the browselink in case the language is e.g. right-to-left.</p> </section> <section id="provide-context-hints-for-translators"> <span id="hints"></span><h3>Provide context hints for translators<a class="headerlink" href="#provide-context-hints-for-translators" title="Link to this heading"></a></h3> <p>In case some translation strings may be translated wrongly because they have multiple meanings, you can add hints which will be shown in the Transifex web-interface:</p> <p><strong>PHP</strong></p> <div class="highlight-php notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="nx">ul</span> <span class="nx">id</span><span class="o">=</span><span class="s2">"translations"</span><span class="o">></span> <span class="o"><</span><span class="nx">li</span> <span class="nx">id</span><span class="o">=</span><span class="s2">"add-new"</span><span class="o">></span> <span class="o"><?</span><span class="nx">php</span> <span class="c1">// TRANSLATORS Will be shown inside a popup and asks the user to add a new file</span> <span class="nx">p</span><span class="p">(</span><span class="nv">$l</span><span class="o">-></span><span class="na">t</span><span class="p">(</span><span class="s1">'Add new file'</span><span class="p">));</span> <span class="cp">?></span> <span class="x"> </li></span> <span class="x"></ul></span> </pre></div> </div> <p><strong>Javascript</strong></p> <div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="c1">// TRANSLATORS name that is appended to copied files with the same name, will be put in parenthesis and appended with a number if it is the second+ copy</span> <span class="kd">var</span><span class="w"> </span><span class="nx">copyNameLocalized</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">t</span><span class="p">(</span><span class="s1">'files'</span><span class="p">,</span><span class="w"> </span><span class="s1">'copy'</span><span class="p">);</span> </pre></div> </div> <p><strong>Vue</strong></p> <p>This covers vue html templates in vue sfc components. For vue js code, see the javascript section.</p> <div class="highlight-html notranslate"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">NcActionCheckbox</span> <span class="na">:checked</span><span class="o">=</span><span class="s">"isRequired"</span><span class="p">></span> <span class="cm"><!-- TRANSLATORS Making this question necessary to be answered when submitting to a form --></span> {{ t('forms', 'Required') }} <span class="p"></</span><span class="nt">NcActionCheckbox</span><span class="p">></span> </pre></div> </div> <p><strong>C++ (Qt)</strong></p> <div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="c1">//: Example text: "Progress of sync process. Shows the currently synced filename"</span> <span class="n">fileProgressString</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tr</span><span class="p">(</span><span class="s">"Syncing %1"</span><span class="p">).</span><span class="n">arg</span><span class="p">(</span><span class="n">allFilenames</span><span class="p">);</span> </pre></div> </div> <p><strong>Android Strings</strong></p> <div class="highlight-xml notranslate"><div class="highlight"><pre><span></span><span class="cm"><!-- TRANSLATORS List of deck boards --></span> <span class="nt"><string</span><span class="w"> </span><span class="na">name=</span><span class="s">"simple_boards"</span><span class="nt">></span>Boards<span class="nt"></string></span> </pre></div> </div> <p><strong>iOS</strong></p> <div class="highlight-swift notranslate"><div class="highlight"><pre><span></span><span class="cm">/* The title on the navigation bar of the Scanning screen. */</span> <span class="s">"wescan.scanning.title"</span> <span class="p">=</span> <span class="s">"Scanning"</span><span class="p">;</span> </pre></div> </div> </section> </section> <section id="adding-translations"> <h2>Adding translations<a class="headerlink" href="#adding-translations" title="Link to this heading"></a></h2> <p>Nextcloud’s translation system is powered by <a class="reference external" href="https://explore.transifex.com/nextcloud/">Transifex</a>. To start translating sign up and enter a group. If your community app should be translated by the <a class="reference external" href="https://explore.transifex.com/nextcloud/">Nextcloud community on Transifex</a> just follow the setup section below.</p> <section id="translation-tool"> <h3>Translation tool<a class="headerlink" href="#translation-tool" title="Link to this heading"></a></h3> <p>The translation tool scrapes the source code for method calls to <strong>t()</strong> or <strong>n()</strong> to extract the strings that should be translated. If you check in minified JS code for example then those method names are also quite common and could cause wrong extractions. For this reason we allow to specify a list of files that the translation tool will not scrape for strings. You simply need to add a file named <code class="file docutils literal notranslate"><span class="pre">.l10nignore</span></code> into the root folder of your app and specify the files one per line:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># compiled vue templates</span> <span class="n">js</span><span class="o">/</span><span class="n">bruteforcesettings</span><span class="o">.</span><span class="n">js</span> </pre></div> </div> </section> <section id="setup-of-the-transifex-sync"> <h3>Setup of the transifex sync<a class="headerlink" href="#setup-of-the-transifex-sync" title="Link to this heading"></a></h3> <p>To setup the transifex sync within the Nextcloud community you need to add first the transifex config to your app folder at <code class="file docutils literal notranslate"><span class="pre">.tx/config</span></code> (please replace <strong>MYAPP</strong> with your apps id):</p> <div class="highlight-ini notranslate"><div class="highlight"><pre><span></span><span class="k">[main]</span> <span class="na">host</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">https://www.transifex.com</span> <span class="na">lang_map</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">th_TH: th, ja_JP: ja, bg_BG: bg, cs_CZ: cs, fi_FI: fi, hu_HU: hu, nb_NO: nb, sk_SK: sk</span> <span class="k">[o:nextcloud:p:nextcloud:r:MYAPP]</span> <span class="na">file_filter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">translationfiles/<lang>/MYAPP.po</span> <span class="na">source_file</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">translationfiles/templates/MYAPP.pot</span> <span class="na">source_lang</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">en</span> <span class="na">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">PO</span> </pre></div> </div> <p>Then create a folder <code class="file docutils literal notranslate"><span class="pre">l10n</span></code> and a file <code class="file docutils literal notranslate"><span class="pre">l10n/.gitkeep</span></code> to create an empty folder which later holds the translations.</p> <p>Add one more file called <code class="file docutils literal notranslate"><span class="pre">.l10nignore</span></code> in root of the repository and the files and folders to ignore for translations. Mostly used to ignore packed js files.</p> <p>Now the GitHub account <a class="reference external" href="https://github.com/nextcloud-bot">@nextcloud-bot</a> needs to get <code class="docutils literal notranslate"><span class="pre">write</span></code> access to your repository. You can invite it from your repository settings:</p> <blockquote> <div><p><code class="docutils literal notranslate"><span class="pre">https://github.com/<user-name>/<repo-name>/settings/access</span></code></p> </div></blockquote> <p>After sending the invitation, please <a class="reference external" href="https://github.com/nextcloud/docker-ci/issues/new/choose">open a ticket using the “Request translations” template</a>.</p> <p>The bot will run every night and only push commits to the following branches branch once there is an update to the translation:</p> <ul class="simple"> <li><p>main</p></li> <li><p>master</p></li> <li><p>stableX (X being the recent 3 versions of Nextcloud Server)</p></li> </ul> <p>You can overwrite this list by creating a file <code class="docutils literal notranslate"><span class="pre">.tx/backport</span></code> in your repository with the following content:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">develop</span> <span class="n">stable</span> </pre></div> </div> <p>That would sync the translations for the branches (<code class="docutils literal notranslate"><span class="pre">main</span></code> and <code class="docutils literal notranslate"><span class="pre">master</span></code> are added automatically):</p> <ul class="simple"> <li><p>main</p></li> <li><p>master</p></li> <li><p>develop</p></li> <li><p>stable</p></li> </ul> <div class="admonition note"> <p class="admonition-title">Note</p> <p>In general you should enable the <a class="reference external" href="https://help.github.com/articles/configuring-protected-branches/">protected branches feature</a> for those branches. If you do that, you need to grant the <a class="reference external" href="https://github.com/nextcloud-bot">@nextcloud-bot</a> <code class="docutils literal notranslate"><span class="pre">admin</span></code> permissions, but that is only possible for repositories owned by organizations. You can <a class="reference external" href="https://docs.github.com/en/organizations/collaborating-with-groups-in-organizations/creating-a-new-organization-from-scratch">create your own organization</a></p> </div> <p>If you need help just <a class="reference external" href="https://github.com/nextcloud/docker-ci/issues/new/choose">open a ticket with the request</a> and we can also guide you through the steps.</p> </section> <section id="manual-translation"> <h3>Manual translation<a class="headerlink" href="#manual-translation" title="Link to this heading"></a></h3> <p>If Transifex is not the right choice or the app is not accepted for translation, generate the gettext strings by yourself by executing our <a class="reference external" href="https://github.com/nextcloud/docker-ci/tree/master/translations/translationtool">translation tool</a> in the app folder:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cd</span> <span class="o">/</span><span class="n">srv</span><span class="o">/</span><span class="n">http</span><span class="o">/</span><span class="n">nextcloud</span><span class="o">/</span><span class="n">apps</span><span class="o">/</span><span class="n">myapp</span> <span class="n">translationtool</span><span class="o">.</span><span class="n">phar</span> <span class="n">create</span><span class="o">-</span><span class="n">pot</span><span class="o">-</span><span class="n">files</span> </pre></div> </div> <p>The translation tool requires <strong>gettext</strong>, installable via:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="n">gettext</span> </pre></div> </div> <p>The above tool generates a template that can be used to translate all strings of an app. This template is located in the folder <code class="file docutils literal notranslate"><span class="pre">translationfiles/template/</span></code> with the name <code class="file docutils literal notranslate"><span class="pre">myapp.pot</span></code>. It can be used by your favored translation tool which then creates a <code class="file docutils literal notranslate"><span class="pre">.po</span></code> file. The <code class="file docutils literal notranslate"><span class="pre">.po</span></code> file needs to be placed in a folder named like the language code with the app name as filename - for example <code class="file docutils literal notranslate"><span class="pre">translationfiles/es/myapp.po</span></code>. After this step the tool needs to be invoked to transfer the po file into our own fileformat that is more easily readable by the server code:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">translationtool</span><span class="o">.</span><span class="n">phar</span> <span class="n">convert</span><span class="o">-</span><span class="n">po</span><span class="o">-</span><span class="n">files</span> </pre></div> </div> <p>Now the following folder structure is available:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">myapp</span><span class="o">/</span><span class="n">l10n</span> <span class="o">|--</span> <span class="n">es</span><span class="o">.</span><span class="n">js</span> <span class="o">|--</span> <span class="n">es</span><span class="o">.</span><span class="n">json</span> <span class="n">myapp</span><span class="o">/</span><span class="n">translationfiles</span> <span class="o">|--</span> <span class="n">es</span> <span class="o">|</span> <span class="o">|--</span> <span class="n">myapp</span><span class="o">.</span><span class="n">po</span> <span class="o">|--</span> <span class="n">templates</span> <span class="o">|--</span> <span class="n">myapp</span><span class="o">.</span><span class="n">pot</span> </pre></div> </div> <p>You then just need the <code class="file docutils literal notranslate"><span class="pre">.json</span></code> and <code class="file docutils literal notranslate"><span class="pre">.js</span></code> files for a working localized app.</p> </section> </section> </section> </div> </div> <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> <a href="css.html" class="btn btn-neutral float-left" title="CSS" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> <a href="theming.html" class="btn btn-neutral float-right" title="Theming support" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> </div> <hr/> <div role="contentinfo"> <p>© Copyright 2024 Nextcloud GmbH.</p> </div> </footer> </div> </div> </section> </div> <script> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>