nicolabs.net/docs/articles/how-organise-xml-resources.html
2024-05-23 21:44:09 +02:00

14 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title> nicolabs | How to organise XML resources </title> <meta name="description" content=" Work in progress... "> <meta name="keywords" content="android, development, java, javascript, python, web"> <meta name="HandheldFriendly" content="True"> <meta name="MobileOptimized" content="320"> <!-- Social: Facebook / Open Graph --> <meta property="og:type" content="article"> <meta property="article:author" content="nicobo"> <meta property="article:section" content=""> <meta property="article:tag" content=""> <meta property="article:published_time" content="2011-12-16 20:24:21 +0100"> <meta property="og:url" content="https://www.nicolabs.net/articles/how-organise-xml-resources"> <meta property="og:title" content=" nicolabs | How to organise XML resources "> <meta property="og:image" content="https://www.nicolabs.net"> <meta property="og:description" content=" Work in progress... "> <meta property="og:site_name" content="nicobo"> <meta property="og:locale" content="en_US"> <!-- Social: Twitter --> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:site" content="nic0b0"> <meta name="twitter:title" content=" nicolabs | How to organise XML resources "> <meta name="twitter:description" content=" Work in progress... "> <meta name="twitter:image:src" content="https://www.nicolabs.net"> <!-- Social: Google+ / Schema.org --> <meta itemprop="name" content=" nicolabs | How to organise XML resources "> <meta itemprop="description" content=" Work in progress... "> <meta itemprop="image" content="https://www.nicolabs.net"> <!-- rel prev and next --> <link rel="stylesheet" href="/assets/css/main.css"> <!-- Canonical link tag --> <link rel="canonical" href="https://www.nicolabs.net/articles/how-organise-xml-resources"> <link type="application/atom+xml" rel="alternate" href="https://www.nicolabs.net/feed.xml" title="nicolabs" /> <script type="text/javascript"> var disqus_shortname = 'nicolabs'; </script> <!-- Enable displaying pictures in full size using the Fullscreen API --> <!-- A polyfill that also simplifies the API. TODO maybe there are others closer to the norm and with more features. Still chances are this will not work on iPhone without using a full-fledged Js library. --> <script src="/assets/lib/screenfull.js/dist/screenfull.min.js"></script> <!-- This code selects which elements and how fullscreen is triggered --> <script> document.addEventListener("DOMContentLoaded", function(event) { var els = document.getElementsByClassName("plantuml"); for ( var e=0 ; e<els.length ; e++ ) { var el = els[e]; el.addEventListener('click', function() { if (screenfull.isEnabled) { screenfull.toggle(el); el.classList.toggle("fullscreen"); } else { console.log("Fullscreen not supported"); } }); } }); </script> <script> window.onscroll = function() { if (document.body.scrollTop > 0 || document.documentElement.scrollTop > 0) { document.querySelector('.site-header').classList.add('site-header-pinned'); } else { document.querySelector('.site-header').classList.remove('site-header-pinned'); } }; </script> </head> <body> <main class="wrapper"> <header class="site-header"> <nav class="nav"> <div class="container"> <h1 class="logo"><a href="/">nico<span>labs</span></a></h1> <ul class="navbar"> <li><a href="/about">about</a></li> <li><a href="/articles">articles</a></li> <li><a href="/feed.xml">feed</a></li> </ul> </div> </nav> </header> <article class="post container" itemscope itemtype="http://schema.org/BlogPosting"> <header class="post-header"> <h1 class="post-title" itemprop="name headline">How to organise XML resources</h1> <p class="post-meta"> <a href="https://github.com/nicolabs/nicolabs.github.io/commits/master/_posts/2011-12-16-How-to-organise-XML-resources.md" title="Read full history of this post"> <time class="datePublished" datetime="2011-12-16T20:24:21+01:00" itemprop="datePublished">Dec 16, 2011</time> </a> <span class="post-meta-separator"></span> <span itemprop="read_time"> 7 minutes read </span> <span class="post-meta-separator"></span> <span itemprop="maturity"><a href="/2016/Migrating-from-Drupal-to-Jekyll" title="Maturity of this article : draft < good < stable or deprecated&#xa;Click for the explanation.">Maturity : <span class="maturity-label maturity-stable" title="Maturity of this article : draft < good < stable or deprecated">stable</span> </span></a> </p> </header> <div class="post-content" itemprop="articleBody"> <blockquote> <p>This is a technical article aimed at <strong>Android</strong> developers. It does not require a lot of background on Android XML resources, but if you dont understand something just check out <a href="http://developer.android.com/guide/topics/resources/index.html">the official docs</a>.</p> </blockquote> <p>The first time I read Android developer docs, there was something that was unclear to me : <strong>what resource to put in which XML file</strong>.</p> <p>In this article, I will focus on resources in <code class="language-plaintext highlighter-rouge">res/values/</code> and give some hints about how to name your XML resource files and what kind of resource to put inside.</p> <h2 id="how-do-xml-resources-work">How do XML resources work</h2> <p>With the Android SDK, the resource class <code class="language-plaintext highlighter-rouge">R</code> is automatically generated as a hierarchy of constants that reflect resources declared by the developer in XML files.</p> <p>Each constant matches an available resource and can be passed to the API in many places.</p> <p>Here is what the Androids developers guide says about resources in <code class="language-plaintext highlighter-rouge">res/values/</code> :</p> <blockquote> <p>XML files that contain simple values, such as strings, integers, and colors.</p> <p>Whereas XML resource files in other <code class="language-plaintext highlighter-rouge">res/</code> subdirectories define a single resource based on the XML filename, files in the <code class="language-plaintext highlighter-rouge">values/</code> directory describe multiple resources. For a file in this directory, each child of the <code class="language-plaintext highlighter-rouge">&lt;resources&gt;</code> element defines a single resource. &gt;For example, a <code class="language-plaintext highlighter-rouge">&lt;string&gt;</code> element creates an R.string resource and a <code class="language-plaintext highlighter-rouge">&lt;color&gt;</code> element creates an <code class="language-plaintext highlighter-rouge">R.color</code> resource.</p> <p>Because each resource is defined with its own XML element, you can name the file whatever you want and place different resource types in one file. However, for clarity, you might want to place unique resource types in different files. For example, here are some filename conventions for resources you can create in this directory:</p> <ul> <li>arrays.xml for resource arrays (<a href="http://developer.android.com/guide/topics/resources/more-resources.html#TypedArray">typed arrays</a>).</li> <li>colors.xml for <a href="http://developer.android.com/guide/topics/resources/more-resources.html#Color">color values</a></li> <li>dimens.xml for <a href="http://developer.android.com/guide/topics/resources/more-resources.html#Dimension">dimension values</a>.</li> <li>strings.xml for <a href="http://developer.android.com/guide/topics/resources/string-resource.html">string values</a>.</li> <li>styles.xml for <a href="http://developer.android.com/guide/topics/resources/style-resource.html">styles</a>.</li> </ul> <p>See <a href="http://developer.android.com/guide/topics/resources/string-resource.html">String Resources</a>, <a href="http://developer.android.com/guide/topics/resources/style-resource.html">Style Resource</a>, and <a href="http://developer.android.com/guide/topics/resources/more-resources.html">More Resource Types</a>.</p> </blockquote> <p>What is important to understand is that a resource accessed through i.e. <code class="language-plaintext highlighter-rouge">R.string.myValue</code> does <strong>not</strong> have to be declared in a file named <code class="language-plaintext highlighter-rouge">strings.xml</code>. As stated above, you can name the files in <code class="language-plaintext highlighter-rouge">res/values/</code> as it fits you.</p> <p>Any <em>string</em>-typed resource named <strong>myValue</strong> declared in any XML file under <code class="language-plaintext highlighter-rouge">res/values/</code> will be found as <code class="language-plaintext highlighter-rouge">R</code><em><code class="language-plaintext highlighter-rouge">.string</code></em><strong><code class="language-plaintext highlighter-rouge">.myValue</code></strong>.</p> <p>For example, a value to be accessed as <code class="language-plaintext highlighter-rouge">R.string.app_name</code> in Java and as <code class="language-plaintext highlighter-rouge">@string/app_name</code> in XML layouts may be declared in <code class="language-plaintext highlighter-rouge">res/values/static.xml</code> as :</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;string</span> <span class="na">name=</span><span class="s">"app_name"</span><span class="nt">&gt;</span>SwitchDataSwitch<span class="nt">&lt;/string&gt;</span>
...
<span class="nt">&lt;/resources&gt;</span>
</code></pre></div></div> <h2 id="clearing-the-way">Clearing the way</h2> <p>Not really knowing where I was going, I started out with a single <code class="language-plaintext highlighter-rouge">res/values/strings.xml</code>, as it is used in many code samples. It put all strings in it.</p> <p>Things became tricky when I found that I needed both plain strings and arrays of strings to be translated, and also static strings that should not be translated but still present as XML resources.</p> <h3 id="some-problems">Some problems</h3> <p>In my case I had only one or two arrays of strings so it was overwhelming and more confusion to put them in a separate file just because they were of a different type.</p> <p>Another problem was accessing constant values from both XML layout and Java code. They are constant strings for internal use only, but in order to avoid duplicate declarations I decided to make them available as XML resources. I wanted those resources to be clearly separated from other, user visible, resources like GUI labels.</p> <p>Another thing adding to the fog was the fact that, in derivate files (e.g. <code class="language-plaintext highlighter-rouge">strings-fr.xml</code> is derivated from <code class="language-plaintext highlighter-rouge">strings.xml</code>), you only want to find values relevant for the given file. For instance, if you put all values of type string in the same file but only a part of them should be internationalized, you would have a gap between the original and derivated files not only by the translated values but also by the list of values they declare. When coming back to the project after a long time, you might have a hard time remembering why there is this gap.</p> <h3 id="a-solution-">A solution ?</h3> <p>So should I put any type of resources in the same file since they must be translated together ?</p> <p>Should I leave static strings together with dynamic ones since they have same type (string) ?</p> <p>After some time developing, I found out that the best solution was to separate the resources by destination (= usage), not by type.</p> <p>In my case I ended up with the following files :</p> <ul> <li><code class="language-plaintext highlighter-rouge">res/values/strings.xml</code> : contains all text to be translated, whatever the type (having both strings and arrays of strings sounds rational)</li> <li><code class="language-plaintext highlighter-rouge">res/values/strings-[ln].xml</code> : contains text translated in <em>[ln]</em> ; same content as <code class="language-plaintext highlighter-rouge">strings.xml</code> (although translated)</li> <li><code class="language-plaintext highlighter-rouge">res/values/static.xml</code> : contains all static constants for internal use that are accessed both from XML layouts and Java code</li> </ul> <p>In the end, this almost matches whats recommended in the developers guide, apart from the arrays.xml file, which should not exist from the point of view explained here.</p> <h3 id="a-concrete-example">A concrete example</h3> <p><a href="http://developer.android.com/reference/android/preference/ListPreference.html"><code class="language-plaintext highlighter-rouge">ListPreferences</code></a> is a GUI component that displays a list of values for the user to choose. As an XML resource, it makes use of two strings arrays : one for the strings to display for each item and the other for their internal values. Obviously the internal values must not be internationalized, whether the strings displayed to the user have to.</p> <p>So the definition of the strings would go to <code class="language-plaintext highlighter-rouge">res/values/strings.xml</code> :</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;string-array</span> <span class="na">name=</span><span class="s">"pref_switchmode_entries"</span><span class="nt">&gt;</span>
<span class="nt">&lt;item</span> <span class="nt">&gt;</span>Use internal method<span class="nt">&lt;/item&gt;</span>
<span class="nt">&lt;item</span> <span class="nt">&gt;</span>Use DataSwitch application<span class="nt">&lt;/item&gt;</span>
<span class="nt">&lt;/string-array&gt;</span>
</code></pre></div></div> <p>And the definition of the internal values would go to <code class="language-plaintext highlighter-rouge">res/values/static.xml</code> :</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;string-array</span> <span class="na">name=</span><span class="s">"pref_switchmode_values"</span><span class="nt">&gt;</span>
<span class="nt">&lt;item&gt;</span>internal<span class="nt">&lt;/item&gt;</span>
<span class="nt">&lt;item&gt;</span>dataswitch<span class="nt">&lt;/item&gt;</span>
<span class="nt">&lt;/string-array&gt;</span>
</code></pre></div></div> <h2 id="references">References</h2> <ul> <li><a href="http://developer.android.com/guide/topics/resources/index.html">Application Resources @ Android developers</a></li> </ul> <aside class="tags"> <ul class="tags"> <li class="tag"><a href="/tags#android">#android</a></li> <li class="tag"><a href="/tags#xml">#XML</a></li> </ul> </aside> <!--aside class="share"> <strong>Share this :</strong> <a href="http://twitter.com/share?text=How to organise XML resources&amp;url=https://www.nicolabs.net/articles/how-organise-xml-resources&amp;hashtags=web,dev,blog,soudev&amp;via=nic0b0" onclick="window.open(this.href, 'twitter-share', 'width=550,height=235');return false;">Twitter</a> <a href="https://www.facebook.com/sharer/sharer.php?u=https://www.nicolabs.net/articles/how-organise-xml-resources" onclick="window.open(this.href, 'facebook-share', 'width=550,height=235');return false;">Facebook</a> </aside--> </div> </article> <footer class="site-footer"> <div class="container"> <small class="pull-left">&copy;2024 All rights reserved. Graphic banner from https://showyourstripes.info</small> <small class="pull-right">by <a rel="me" href="/about#contact">@nicobo</a></small> </div> </footer> </main> </body> </html>