source: trunk/eraser6/Eraser.Util/Localisation.cs @ 1268

Revision 1268, 7.2 KB checked in by lowjoel, 5 years ago (diff)

Reverted r1258 and r1254-r1255; this is in the EncryptedSettings? branch.

  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25
26using System.IO;
27using System.Reflection;
28using System.Globalization;
29using System.Windows.Forms;
30using System.Diagnostics;
31using System.Resources;
32using System.Threading;
33
34namespace Eraser.Util
35{
36    /// <summary>
37    /// Internationalisation class. Instead of calling GetString on all strings, just
38    /// call S._(string) or S._(string, object) for plurals
39    /// </summary>
40    public static class S
41    {
42        /// <summary>
43        /// Translates the localisable string to the set localised string.
44        /// </summary>
45        /// <param name="str">The string to localise.</param>
46        /// <returns>A localised string, or str if no localisation exists.</returns>
47        public static string _(string str)
48        {
49            return TranslateText(str, Assembly.GetCallingAssembly());
50        }
51
52        /// <summary>
53        /// Translates the localisable string to the localised string, formatting all
54        /// placeholders using composite formatting. This is shorthand for
55        /// <code>string.Format(S._(str), args)</code>
56        /// </summary>
57        /// <param name="str">The string to localise.</param>
58        /// <param name="args">Arguments for the composite formatting call.</param>
59        /// <returns>The formatted and localised string.</returns>
60        /// <remarks>The localised string is retrieved before formatting.</remarks>
61        public static string _(string str, params object[] args)
62        {
63            //Get the localised version of the input string.
64            string localStr = TranslateText(str, Assembly.GetCallingAssembly());
65
66            //Format the string.
67            return string.Format(CultureInfo.CurrentCulture, localStr, args);
68        }
69
70        /// <summary>
71        /// Returns true if the given control is right-to-left reading.
72        /// </summary>
73        /// <param name="control">The control to query.</param>
74        /// <returns>True if the control is right-to-left reading.</returns>
75        public static bool IsRightToLeft(Control control)
76        {
77            if (control == null)
78                return CultureInfo.CurrentCulture.TextInfo.IsRightToLeft;
79
80            switch (control.RightToLeft)
81            {
82                case RightToLeft.No:
83                    return false;
84                case RightToLeft.Yes:
85                    return true;
86                default:
87                    return IsRightToLeft(control.Parent);
88            }
89        }
90
91        /// <summary>
92        /// Translates the localisable string to the set localised string.
93        /// </summary>
94        /// <param name="str">The string to localise.</param>
95        /// <param name="assembly">The assembly from which localised resource satellite
96        /// assemblies should be loaded from.</param>
97        /// <returns>A localised string, or str if no localisation exists.</returns>
98        public static string TranslateText(string str, Assembly assembly)
99        {
100            //If the string is empty, forget it!
101            if (str.Length == 0)
102                return str;
103
104            //First get the dictionary mapping assemblies and ResourceManagers (i.e. pick out
105            //the dictionary with ResourceManagers representing the current culture.)
106            if (!managers.ContainsKey(Thread.CurrentThread.CurrentUICulture))
107                managers[Thread.CurrentThread.CurrentUICulture] =
108                    new Dictionary<Assembly, ResourceManager>();
109            Dictionary<Assembly, ResourceManager> assemblies = managers[
110                Thread.CurrentThread.CurrentUICulture];
111
112            //Then look for the ResourceManager dealing with the calling assembly's
113            //resources
114            ResourceManager res = null;
115            if (!assemblies.ContainsKey(assembly))
116            {
117                //Load the resource DLL. The resource DLL is located in the <LanguageName-RegionName>
118                //subfolder of the folder containing the main assembly
119                string languageID = string.Empty;
120                Assembly languageAssembly = LoadLanguage(Path.GetDirectoryName(
121                    Assembly.GetEntryAssembly().Location), Thread.CurrentThread.CurrentUICulture,
122                    assembly, out languageID);
123
124                //If we found the language assembly to load, then we load it directly, otherwise
125                //fall back to the invariant culture.
126                string resourceName = Path.GetFileNameWithoutExtension(assembly.Location) +
127                    ".Strings" + (languageID.Length != 0 ? ("." + languageID) : "");
128                res = new ResourceManager(resourceName,
129                    languageAssembly != null ? languageAssembly : assembly);
130                assemblies[assembly] = res;
131            }
132            else
133                res = assemblies[assembly];
134
135            string result = res.GetString(Escape(str), Thread.CurrentThread.CurrentUICulture);
136            return result == null ? str : Unescape(result);
137        }
138
139        /// <summary>
140        /// Replaces non-printable codes used in the string to translate into translatable placeholders.
141        /// </summary>
142        /// <param name="str">The string to escape</param>
143        /// <returns>An escaped string</returns>
144        private static string Escape(string str)
145        {
146            return str.Replace("\n", "\\n").Replace("\r", "\\r");
147        }
148
149        /// <summary>
150        /// Replaces all escape codes used in the translated string into real character codes.
151        /// </summary>
152        /// <param name="str">The string to unescape</param>
153        /// <returns>An unescaped string</returns>
154        private static string Unescape(string str)
155        {
156            return str.Replace("\\n", "\n").Replace("\\r", "\r");
157        }
158
159        /// <summary>
160        /// Looks in the folder denoted by <paramref name="path"/> for the resource providing
161        /// resources for <paramref name="culture"/>. The name of the resource DLL will be the
162        /// culture name &gt;languagecode2-country/regioncode2&lt;.
163        /// </summary>
164        /// <param name="directory">The directory to look for assemblies in. Subfolders are not
165        /// included.</param>
166        /// <param name="culture">The culture to load.</param>
167        /// <param name="assembly">The assembly to look for localised resources for.</param>
168        /// <returns>An assembly containing the required resources, or null.</returns>
169        private static Assembly LoadLanguage(string directory, CultureInfo culture, Assembly assembly,
170            out string languageID)
171        {
172            languageID = string.Empty;
173            string path = string.Empty;
174            while (culture != CultureInfo.InvariantCulture)
175            {
176                path = Path.Combine(directory, culture.Name);
177                if (System.IO.Directory.Exists(path))
178                {
179                    string assemblyPath = Path.Combine(path,
180                        Path.GetFileNameWithoutExtension(assembly.Location) + ".resources.dll");
181                    if (System.IO.File.Exists(assemblyPath))
182                    {
183                        languageID = culture.Name;
184                        return Assembly.LoadFile(assemblyPath);
185                    }
186                }
187                culture = culture.Parent;
188            }
189
190            return null;
191        }
192
193        private static Dictionary<CultureInfo, Dictionary<Assembly, ResourceManager>> managers =
194            new Dictionary<CultureInfo, Dictionary<Assembly, ResourceManager>>();
195    }
196}
Note: See TracBrowser for help on using the repository browser.