1 /*  Copyright (c) 2003-2014 Xfce Development Team
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  * Boston, MA 02110-1301, USA.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 
23 #include <string.h>
24 #include <time.h>
25 
26 #include "weather-parsers.h"
27 #include "weather-data.h"
28 #include "weather.h"
29 #include "weather-translate.h"
30 
31 #define DAY_LOC_N (sizeof(gchar) * 100)
32 #define NODATA "NODATA"
33 
34 
35 static const gchar *moon_phases[] = {
36     /* TRANSLATORS: Moon phases */
37     N_("New moon"),
38     N_("Waxing crescent"),
39     N_("First quarter"),
40     N_("Waxing gibbous"),
41     N_("Full moon"),
42     N_("Waning gibbous"),
43     N_("Third quarter"),
44     N_("Waning crescent"),
45     NULL
46 };
47 #define NUM_MOON_PHASES (sizeof(moon_phases) / sizeof(gchar *))
48 
49 typedef struct {
50     gint id;
51     gchar *symbol;
52     gchar *desc;
53     gchar *night_desc;
54 } symbol_desc;
55 
56 static const symbol_desc symbol_to_desc[] = {
57     /*
58      * TRANSLATORS: How these symbols are named and defined is explained at
59      * http://om.yr.no/forklaring/symbol/ and https://api.met.no/faq.html#symbols.
60      * To be more concise / shorter, the plugin uses names that deviate a bit from yr.no, so that
61      * they fit well in the tooltip, forecast tab etc.
62      *
63      * More information can be obtained from the following pages:
64      * http://www.theweathernetwork.com/weathericons/?product=weathericons&pagecontent=index
65      * http://www.theweathernetwork.com/index.php?product=help&placecode=cabc0164&pagecontent=helpicons
66      * http://www.mir-co.net/sonstiges/wetterausdruecke.htm
67      * The latter page is in German, but it contains a symbol table with Norwegian descriptions.
68      */
69     {  1, "SUN",                 N_("Sunny"),                      N_("Clear")                      },
70     {  2, "LIGHTCLOUD",          N_("Lightly cloudy"),             N_("Lightly cloudy")             },
71     {  3, "PARTLYCLOUD",         N_("Partly cloudy"),              N_("Partly cloudy")              },
72     {  4, "CLOUD",               N_("Cloudy"),                     N_("Cloudy")                     },
73 
74     /*
75      * http://www.theweathernetwork.com/weathericons/?product=weathericons&pagecontent=index:
76      *   "Showers – Some sun is expected, interspersed with showers from
77      *    time to time. As opposed to rain, showers describe liquid
78      *    precipitation that can vary greatly in intensity over a short
79      *    amount of time. [...] Precipitation may be locally heavy for
80      *    short amounts of time."
81      */
82     {  5, "LIGHTRAINSUN",        N_("Rain showers"),               N_("Rain showers")               },
83 
84     /*
85      * http://www.theweathernetwork.com/weathericons/?product=weathericons&pagecontent=index:
86      *   "Thunder Showers - Intermittent rain showers with thunder and lightning, generally
87      *    short-lived."
88      */
89     {  6, "LIGHTRAINTHUNDERSUN", N_("Thunder showers"),            N_("Thunder showers")            },
90 
91     /* Analogues to "Rain showers" */
92     {  7, "SLEETSUN",            N_("Sleet showers"),              N_("Sleet showers")              },
93     {  8, "SNOWSUN",             N_("Snow showers"),               N_("Snow showers")               },
94 
95     /* It's raining, usually incessantly, but not heavily. */
96     {  9, "LIGHTRAIN",           N_("Light rain"),                 N_("Light rain")                 },
97 
98     /* Heavy, usually incessant rain. met.no now uses "heavy rain", but personally I find light
99      * rain and rain somewhat better. Symbol names indicate this is the way met.no did it some
100      * time ago. */
101     { 10, "RAIN",                N_("Rain"),                       N_("Rain")                       },
102 
103     { 11, "RAINTHUNDER",         N_("Rain with thunder"),          N_("Rain with thunder")          },
104 
105     /* Sleet is a mixture of rain and snow, but it's not hail. */
106     { 12, "SLEET",               N_("Sleet"),                      N_("Sleet")                      },
107 
108     { 13, "SNOW",                N_("Snow"),                       N_("Snow")                       },
109 
110     /*
111      * http://en.wikipedia.org/wiki/Thundersnow:
112      *   "Thundersnow, also known as a winter thunderstorm or a thunder snowstorm, is a relatively
113      *    rare kind of thunderstorm with snow falling as the primary precipitation instead of
114      *    rain. It typically falls in regions of strong upward motion within the cold sector of an
115      *    extratropical cyclone."
116      */
117     { 14, "SNOWTHUNDER",         N_("Thundersnow"),                N_("Thundersnow")                },
118 
119     { 15, "FOG",                 N_("Fog"),                        N_("Fog")                        },
120 
121     /* Symbols 16-19 are used for polar days (unused beginning with API version 1.2) */
122     { 16, "SUN",                 N_("Sunny"),                      N_("Clear")                      },
123     { 17, "LIGHTCLOUD",          N_("Lightly cloudy"),             N_("Lightly cloudy")             },
124     { 18, "LIGHTRAINSUN",        N_("Rain showers"),               N_("Rain showers")               },
125     { 19, "SNOWSUN",             N_("Snow showers"),               N_("Snow showers")               },
126 
127     /* Same as symbols 1-15, but with thunder */
128     { 20, "SLEETSUNTHUNDER",     N_("Sleet showers with thunder"), N_("Sleet showers with thunder") },
129     { 21, "SNOWSUNTHUNDER",      N_("Snow showers with thunder"),  N_("Snow showers with thunder")  },
130     { 22, "LIGHTRAINTHUNDER",    N_("Light rain with thunder"),    N_("Light rain with thunder")    },
131     { 23, "SLEETTHUNDER",        N_("Sleet with thunder"),         N_("Sleet with thunder")         },
132 };
133 
134 #define NUM_SYMBOLS (sizeof(symbol_to_desc) / sizeof(symbol_to_desc[0]))
135 
136 
137 /*
138  * API version 1.2, published in May 2014, introduced new symbols. We
139  * try to match these with existing symbols, in order to be compatible
140  * with existing icon themes and to maintain translation completeness.
141  *
142  * See https://api.met.no/weatherapi/weathericon/1.1/documentation
143  * for a list of symbols. For a list of symbols with descriptions,
144  * see http://om.yr.no/forklaring/symbol.
145  */
146 static gint
replace_symbol_id(gint id)147 replace_symbol_id(gint id)
148 {
149     /* Symbol ids greater than 100 are used for indicating polar
150      * night. These ids are over the ordinary id + 100. Since we
151      * don't support polar icons, we can simply subtract 100 to
152      * get the non-polar symbol ids.
153      */
154     if (id > 100)
155         id -= 100;
156 
157     switch (id) {
158     case 24: return 22; /* Light rain showers and thunder */
159     case 25: return 6;  /* Heavy rain showers and thunder */
160     case 26: return 20; /* Light sleet showers and thunder */
161     case 27: return 20; /* Heavy sleet showers and thunder */
162     case 28: return 21; /* Light snow showers and thunder */
163     case 29: return 21; /* Heavy snow showers and thunder */
164     case 30: return 22; /* Light rain and thunder */
165     case 31: return 23; /* Light sleet and thunder */
166     case 32: return 23; /* Heavy sleet and thunder */
167     case 33: return 14; /* Light snow and thunder */
168     case 34: return 14; /* Heavy snow and thunder */
169 
170     /* symbols 35-39 are unused */
171 
172     case 40: return 5;  /* Light rain showers */
173     case 41: return 5;  /* Heavy rain showers */
174     case 42: return 7;  /* Light sleet showers */
175     case 43: return 7;  /* Heavy sleet showers */
176     case 44: return 8;  /* Light snow showers */
177     case 45: return 8;  /* Heavy snow showers */
178     case 46: return 9;  /* Light rain */
179     case 47: return 12; /* Light sleet */
180     case 48: return 12; /* Heavy sleet */
181     case 49: return 13; /* Light snow */
182     case 50: return 13; /* Heavy snow */
183     default: return id;
184     }
185 }
186 
187 
188 const gchar *
get_symbol_for_id(guint id)189 get_symbol_for_id(guint id)
190 {
191     if (G_UNLIKELY(id < 1))
192         return NODATA;
193 
194     if (id >= NUM_SYMBOLS)
195         id = replace_symbol_id(id);
196 
197     if (id < NUM_SYMBOLS)
198         return symbol_to_desc[id-1].symbol;
199 
200     return NODATA;
201 }
202 
203 
204 const gchar *
translate_desc(const gchar * desc,const gboolean nighttime)205 translate_desc(const gchar *desc,
206                const gboolean nighttime)
207 {
208     guint i;
209 
210     for (i = 0; i < NUM_SYMBOLS; i++) {
211         if (!strcmp(desc, symbol_to_desc[i].symbol)) {
212             if (nighttime)
213                 return _(symbol_to_desc[i].night_desc);
214             else
215                 return _(symbol_to_desc[i].desc);
216         }
217     }
218     return desc;
219 }
220 
221 
222 const gchar *
translate_moon_phase(const gchar * moon_phase)223 translate_moon_phase(const gchar *moon_phase)
224 {
225     guint i;
226 
227     for (i = 0; i < NUM_MOON_PHASES; i++) {
228         if (!strcmp(moon_phase, moon_phases[i])) {
229             return _(moon_phases[i]);
230         }
231     }
232     return moon_phase;
233 }
234 
235 
236 gchar *
translate_day(const gint weekday)237 translate_day(const gint weekday)
238 {
239     struct tm time_tm;
240     gchar *day_loc;
241     int len;
242 
243     if (weekday < 0 || weekday > 6)
244         return NULL;
245 
246     time_tm.tm_wday = weekday;
247 
248     day_loc = g_malloc(DAY_LOC_N);
249 
250     len = strftime(day_loc, DAY_LOC_N, "%A", &time_tm);
251     day_loc[len] = 0;
252     if (!g_utf8_validate(day_loc, -1, NULL)) {
253         gchar *utf8 = g_locale_to_utf8(day_loc, -1, NULL, NULL, NULL);
254         g_free(day_loc);
255         day_loc = utf8;
256     }
257 
258     return day_loc;
259 }
260