libgweather r300 - in trunk: . data libgweather



Author: danw
Date: Mon Aug  4 12:04:12 2008
New Revision: 300
URL: http://svn.gnome.org/viewvc/libgweather?rev=300&view=rev

Log:
	* data/Locations.xml.in:
	* data/locations.dtd: add information about timezones

	* libgweather/parser.c: new Locations.xml.in parser

	* libgweather/gweather-location.c: opaque replacement for
	WeatherLocation, based on the new parser

	* libgweather/location-entry.c: Autocompleting location-selecting
	entry

	* libgweather/gweather-timezone.c: type representing a timezone

	* libgweather/timezone-menu.c: New widget for selecting
	a (localized) timezone.

	* libgweather/gweather-xml.c: use the new parser internally (but
	convert to WeatherLocation externally)


Added:
   trunk/libgweather/gweather-location.c
   trunk/libgweather/gweather-location.h
   trunk/libgweather/gweather-timezone.c
   trunk/libgweather/gweather-timezone.h
   trunk/libgweather/location-entry.c
   trunk/libgweather/location-entry.h
   trunk/libgweather/parser.c
   trunk/libgweather/parser.h
   trunk/libgweather/test_locations.c
   trunk/libgweather/timezone-menu.c
   trunk/libgweather/timezone-menu.h
Modified:
   trunk/ChangeLog
   trunk/data/Locations.xml.in
   trunk/data/locations.dtd
   trunk/libgweather/   (props changed)
   trunk/libgweather/Makefile.am
   trunk/libgweather/gweather-xml.c
   trunk/libgweather/weather-priv.h
   trunk/libgweather/weather.h

Modified: trunk/data/Locations.xml.in
==============================================================================
--- trunk/data/Locations.xml.in	(original)
+++ trunk/data/Locations.xml.in	Mon Aug  4 12:04:12 2008
@@ -12,6 +12,9 @@
         -->
       <iso-code>DZ</iso-code>
       <fips-code>AG</fips-code>
+      <timezones>
+        <timezone id="Africa/Algiers" />
+      </timezones>
       <tz-hint>Africa/Algiers</tz-hint>
       <city>
         <!-- Translators: this is a city in Algeria -->
@@ -373,6 +376,9 @@
         -->
       <iso-code>AO</iso-code>
       <fips-code>AO</fips-code>
+      <timezones>
+        <timezone id="Africa/Luanda" />
+      </timezones>
       <tz-hint>Africa/Luanda</tz-hint>
       <city>
         <!-- Translators: this is the capital of Angola -->
@@ -395,6 +401,9 @@
         -->
       <iso-code>BJ</iso-code>
       <fips-code>BN</fips-code>
+      <timezones>
+        <timezone id="Africa/Porto-Novo" />
+      </timezones>
       <tz-hint>Africa/Porto-Novo</tz-hint>
       <city>
         <!-- Translators: this is a city in Benin -->
@@ -436,6 +445,9 @@
         -->
       <iso-code>BW</iso-code>
       <fips-code>BC</fips-code>
+      <timezones>
+        <timezone id="Africa/Gaborone" />
+      </timezones>
       <tz-hint>Africa/Gaborone</tz-hint>
       <city>
         <!-- Translators: this is a city in Botswana -->
@@ -562,6 +574,9 @@
         -->
       <iso-code>BF</iso-code>
       <fips-code>UV</fips-code>
+      <timezones>
+        <timezone id="Africa/Ouagadougou" />
+      </timezones>
       <tz-hint>Africa/Ouagadougou</tz-hint>
       <city>
         <!-- Translators: this is a city in Burkina Faso -->
@@ -614,6 +629,9 @@
         -->
       <iso-code>BI</iso-code>
       <fips-code>BY</fips-code>
+      <timezones>
+        <timezone id="Africa/Bujumbura" />
+      </timezones>
       <tz-hint>Africa/Bujumbura</tz-hint>
       <city>
         <!-- Translators: this is a city in Burundi -->
@@ -659,6 +677,9 @@
         -->
       <iso-code>CM</iso-code>
       <fips-code>CM</fips-code>
+      <timezones>
+        <timezone id="Africa/Douala" />
+      </timezones>
       <tz-hint>Africa/Douala</tz-hint>
       <city>
         <!-- Translators: this is a city in Cameroon -->
@@ -714,6 +735,9 @@
         -->
       <iso-code>CV</iso-code>
       <fips-code>CV</fips-code>
+      <timezones>
+        <timezone id="Atlantic/Cape_Verde" />
+      </timezones>
       <tz-hint>Atlantic/Cape_Verde</tz-hint>
       <city>
         <!-- Translators: this is a city in Cape Verde -->
@@ -736,6 +760,9 @@
         -->
       <iso-code>CF</iso-code>
       <fips-code>CT</fips-code>
+      <timezones>
+        <timezone id="Africa/Bangui" />
+      </timezones>
       <tz-hint>Africa/Bangui</tz-hint>
       <city>
         <!-- Translators: this is a city in Central African Republic -->
@@ -790,6 +817,9 @@
         -->
       <iso-code>TD</iso-code>
       <fips-code>CD</fips-code>
+      <timezones>
+        <timezone id="Africa/Ndjamena" />
+      </timezones>
       <tz-hint>Africa/Ndjamena</tz-hint>
       <city>
         <!-- Translators: this is a city in Chad -->
@@ -827,6 +857,9 @@
       <_name>Comoros</_name>
       <iso-code>KM</iso-code>
       <fips-code>CN</fips-code>
+      <timezones>
+        <timezone id="Indian/Comoro" />
+      </timezones>
       <tz-hint>Indian/Comoro</tz-hint>
       <city>
         <!-- Translators: this is a city in Comoros -->
@@ -859,6 +892,26 @@
         -->
       <iso-code>CD</iso-code>
       <fips-code>CG</fips-code>
+      <timezones>
+        <timezone id="Africa/Kinshasa">
+          <!-- Translators: This is the time zone used in the western
+               half of the Democratic Republic of the Congo. The
+               string is only used in places where "Democratic
+               Republic of the Congo" is already clear from context.
+               FIXME: is there an official name for this zone?
+            -->
+          <_name>Western Congo</_name>
+        </timezone>
+        <timezone id="Africa/Lubumbashi">
+          <!-- Translators: This is the time zone used in the eastern
+               half of the Democratic Republic of the Congo. The
+               string is only used in places where "Democratic
+               Republic of the Congo" is already clear from context.
+               FIXME: is there an official name for this zone?
+            -->
+          <_name>Eastern Congo</_name>
+        </timezone>
+      </timezones>
       <city>
         <!-- Translators: this is the capital of Congo, Democratic
              Republic of the
@@ -899,6 +952,9 @@
         -->
       <iso-code>CG</iso-code>
       <fips-code>CF</fips-code>
+      <timezones>
+        <timezone id="Africa/Brazzaville" />
+      </timezones>
       <tz-hint>Africa/Brazzaville</tz-hint>
       <city>
         <!-- Translators: this is the capital of Congo, Republic of the -->
@@ -932,6 +988,9 @@
         -->
       <iso-code>CI</iso-code>
       <fips-code>IV</fips-code>
+      <timezones>
+        <timezone id="Africa/Abidjan" />
+      </timezones>
       <tz-hint>Africa/Abidjan</tz-hint>
       <city>
         <!-- Translators: this is a city in CÃte d'Ivoire -->
@@ -953,6 +1012,9 @@
         -->
       <iso-code>DJ</iso-code>
       <fips-code>DJ</fips-code>
+      <timezones>
+        <timezone id="Africa/Djibouti" />
+      </timezones>
       <tz-hint>Africa/Djibouti</tz-hint>
       <city>
         <!-- Translators: this is a city in Djibouti -->
@@ -1014,6 +1076,9 @@
         -->
       <iso-code>EG</iso-code>
       <fips-code>EG</fips-code>
+      <timezones>
+        <timezone id="Africa/Cairo" />
+      </timezones>
       <tz-hint>Africa/Cairo</tz-hint>
       <city>
         <!-- Translators: this is a city in Egypt -->
@@ -1153,6 +1218,9 @@
         -->
       <iso-code>GQ</iso-code>
       <fips-code>EK</fips-code>
+      <timezones>
+        <timezone id="Africa/Malabo" />
+      </timezones>
       <tz-hint>Africa/Malabo</tz-hint>
       <city>
         <!-- Translators: this is a city in Equatorial Guinea -->
@@ -1184,6 +1252,9 @@
         -->
       <iso-code>ER</iso-code>
       <fips-code>ER</fips-code>
+      <timezones>
+        <timezone id="Africa/Asmara" />
+      </timezones>
       <tz-hint>Africa/Asmara</tz-hint>
     </country>
     <country>
@@ -1195,6 +1266,9 @@
         -->
       <iso-code>ET</iso-code>
       <fips-code>ET</fips-code>
+      <timezones>
+        <timezone id="Africa/Addis_Ababa" />
+      </timezones>
       <tz-hint>Africa/Addis_Ababa</tz-hint>
     </country>
     <country>
@@ -1206,6 +1280,9 @@
       <_name>French Southern Territories</_name>
       <iso-code>TF</iso-code>
       <fips-code>FS</fips-code>
+      <timezones>
+        <timezone id="Indian/Kerguelen" />
+      </timezones>
       <tz-hint>Indian/Kerguelen</tz-hint>
     </country>
     <country>
@@ -1217,6 +1294,9 @@
         -->
       <iso-code>GA</iso-code>
       <fips-code>GB</fips-code>
+      <timezones>
+        <timezone id="Africa/Libreville" />
+      </timezones>
       <tz-hint>Africa/Libreville</tz-hint>
       <city>
         <!-- Translators: this is a city in Gabon -->
@@ -1258,6 +1338,9 @@
         -->
       <iso-code>GM</iso-code>
       <fips-code>GA</fips-code>
+      <timezones>
+        <timezone id="Africa/Banjul" />
+      </timezones>
       <tz-hint>Africa/Banjul</tz-hint>
       <city>
         <!-- Translators: this is the capital of Gambia -->
@@ -1300,6 +1383,9 @@
         -->
       <iso-code>GH</iso-code>
       <fips-code>GH</fips-code>
+      <timezones>
+        <timezone id="Africa/Accra" />
+      </timezones>
       <tz-hint>Africa/Accra</tz-hint>
       <city>
         <!-- Translators: this is the capital of Ghana -->
@@ -1325,6 +1411,9 @@
         -->
       <iso-code>GN</iso-code>
       <fips-code>GV</fips-code>
+      <timezones>
+        <timezone id="Africa/Conakry" />
+      </timezones>
       <tz-hint>Africa/Conakry</tz-hint>
       <city>
         <!-- Translators: this is the capital of Guinea -->
@@ -1366,6 +1455,9 @@
         -->
       <iso-code>GW</iso-code>
       <fips-code>PU</fips-code>
+      <timezones>
+        <timezone id="Africa/Bissau" />
+      </timezones>
       <tz-hint>Africa/Bissau</tz-hint>
       <city>
         <!-- Translators: this is a city in Guinea-Bissau -->
@@ -1387,6 +1479,9 @@
         -->
       <iso-code>KE</iso-code>
       <fips-code>KE</fips-code>
+      <timezones>
+        <timezone id="Africa/Nairobi" />
+      </timezones>
       <tz-hint>Africa/Nairobi</tz-hint>
       <city>
         <!-- Translators: this is a city in Kenya -->
@@ -1449,6 +1544,9 @@
         -->
       <iso-code>LS</iso-code>
       <fips-code>LT</fips-code>
+      <timezones>
+        <timezone id="Africa/Maseru" />
+      </timezones>
       <tz-hint>Africa/Maseru</tz-hint>
     </country>
     <country>
@@ -1462,6 +1560,9 @@
         -->
       <iso-code>LR</iso-code>
       <fips-code>LI</fips-code>
+      <timezones>
+        <timezone id="Africa/Monrovia" />
+      </timezones>
       <tz-hint>Africa/Monrovia</tz-hint>
     </country>
     <country>
@@ -1473,6 +1574,9 @@
         -->
       <iso-code>LY</iso-code>
       <fips-code>LY</fips-code>
+      <timezones>
+        <timezone id="Africa/Tripoli" />
+      </timezones>
       <tz-hint>Africa/Tripoli</tz-hint>
       <city>
         <!-- Translators: this is a city in Libya -->
@@ -1517,6 +1621,9 @@
         -->
       <iso-code>MG</iso-code>
       <fips-code>MA</fips-code>
+      <timezones>
+        <timezone id="Indian/Antananarivo" />
+      </timezones>
       <tz-hint>Indian/Antananarivo</tz-hint>
       <city>
         <!-- Translators: this is a city in Madagascar -->
@@ -1602,6 +1709,9 @@
         -->
       <iso-code>MW</iso-code>
       <fips-code>MI</fips-code>
+      <timezones>
+        <timezone id="Africa/Blantyre" />
+      </timezones>
       <tz-hint>Africa/Blantyre</tz-hint>
     </country>
     <country>
@@ -1614,6 +1724,9 @@
         -->
       <iso-code>ML</iso-code>
       <fips-code>ML</fips-code>
+      <timezones>
+        <timezone id="Africa/Bamako" />
+      </timezones>
       <tz-hint>Africa/Bamako</tz-hint>
     </country>
     <country>
@@ -1626,6 +1739,9 @@
         -->
       <iso-code>MR</iso-code>
       <fips-code>MR</fips-code>
+      <timezones>
+        <timezone id="Africa/Nouakchott" />
+      </timezones>
       <tz-hint>Africa/Nouakchott</tz-hint>
       <city>
         <!-- Translators: this is a city in Mauritania -->
@@ -1653,6 +1769,9 @@
       <_name>Mauritius</_name>
       <iso-code>MU</iso-code>
       <fips-code>MP</fips-code>
+      <timezones>
+        <timezone id="Indian/Mauritius" />
+      </timezones>
       <tz-hint>Indian/Mauritius</tz-hint>
       <city>
         <!-- Translators: this is a city in Mauritius -->
@@ -1690,6 +1809,9 @@
       <_name>Mayotte</_name>
       <iso-code>YT</iso-code>
       <fips-code>MF</fips-code>
+      <timezones>
+        <timezone id="Indian/Mayotte" />
+      </timezones>
       <tz-hint>Indian/Mayotte</tz-hint>
       <city>
         <!-- Translators: this is a city in Mayotte -->
@@ -1720,6 +1842,9 @@
         -->
       <iso-code>MA</iso-code>
       <fips-code>MO</fips-code>
+      <timezones>
+        <timezone id="Africa/Casablanca" />
+      </timezones>
       <tz-hint>Africa/Casablanca</tz-hint>
       <city>
         <!-- Translators: this is a city in Morocco -->
@@ -1864,6 +1989,9 @@
         -->
       <iso-code>MZ</iso-code>
       <fips-code>MZ</fips-code>
+      <timezones>
+        <timezone id="Africa/Maputo" />
+      </timezones>
       <tz-hint>Africa/Maputo</tz-hint>
       <city>
         <!-- Translators: this is a city in Mozambique -->
@@ -1975,6 +2103,9 @@
         -->
       <iso-code>NA</iso-code>
       <fips-code>WA</fips-code>
+      <timezones>
+        <timezone id="Africa/Windhoek" />
+      </timezones>
       <tz-hint>Africa/Windhoek</tz-hint>
       <city>
         <!-- Translators: this is a city in Namibia -->
@@ -2006,6 +2137,9 @@
         -->
       <iso-code>NE</iso-code>
       <fips-code>NG</fips-code>
+      <timezones>
+        <timezone id="Africa/Niamey" />
+      </timezones>
       <tz-hint>Africa/Niamey</tz-hint>
       <city>
         <!-- Translators: this is a city in Niger -->
@@ -2055,6 +2189,9 @@
         -->
       <iso-code>NG</iso-code>
       <fips-code>NI</fips-code>
+      <timezones>
+        <timezone id="Africa/Lagos" />
+      </timezones>
       <tz-hint>Africa/Lagos</tz-hint>
       <city>
         <!-- Translators: this is a city in Nigeria -->
@@ -2137,6 +2274,9 @@
         -->
       <iso-code>RW</iso-code>
       <fips-code>RW</fips-code>
+      <timezones>
+        <timezone id="Africa/Kigali" />
+      </timezones>
       <tz-hint>Africa/Kigali</tz-hint>
       <city>
         <!-- Translators: this is a city in Rwanda -->
@@ -2166,6 +2306,9 @@
       <_name>RÃunion</_name>
       <iso-code>RE</iso-code>
       <fips-code>RE</fips-code>
+      <timezones>
+        <timezone id="Indian/Reunion" />
+      </timezones>
       <tz-hint>Indian/Reunion</tz-hint>
       <city>
         <!-- Translators: this is a city in RÃunion -->
@@ -2210,6 +2353,9 @@
         -->
       <iso-code>ST</iso-code>
       <fips-code>TP</fips-code>
+      <timezones>
+        <timezone id="Africa/Sao_Tome" />
+      </timezones>
       <tz-hint>Africa/Sao_Tome</tz-hint>
     </country>
     <country>
@@ -2221,6 +2367,9 @@
         -->
       <iso-code>SN</iso-code>
       <fips-code>SG</fips-code>
+      <timezones>
+        <timezone id="Africa/Dakar" />
+      </timezones>
       <tz-hint>Africa/Dakar</tz-hint>
       <city>
         <!-- Translators: this is a city in Senegal -->
@@ -2298,6 +2447,9 @@
       <_name>Seychelles</_name>
       <iso-code>SC</iso-code>
       <fips-code>SE</fips-code>
+      <timezones>
+        <timezone id="Indian/Mahe" />
+      </timezones>
       <tz-hint>Indian/Mahe</tz-hint>
       <city>
         <!-- Translators: this is a city in Seychelles -->
@@ -2329,6 +2481,9 @@
         -->
       <iso-code>SL</iso-code>
       <fips-code>SL</fips-code>
+      <timezones>
+        <timezone id="Africa/Freetown" />
+      </timezones>
       <tz-hint>Africa/Freetown</tz-hint>
       <city>
         <!-- Translators: this is the capital of Sierra Leone -->
@@ -2361,6 +2516,9 @@
         -->
       <iso-code>SO</iso-code>
       <fips-code>SO</fips-code>
+      <timezones>
+        <timezone id="Africa/Mogadishu" />
+      </timezones>
       <tz-hint>Africa/Mogadishu</tz-hint>
     </country>
     <country>
@@ -2377,6 +2535,9 @@
         -->
       <iso-code>ZA</iso-code>
       <fips-code>SF</fips-code>
+      <timezones>
+        <timezone id="Africa/Johannesburg" />
+      </timezones>
       <tz-hint>Africa/Johannesburg</tz-hint>
       <city>
         <!-- Translators: this is a city in South Africa -->
@@ -2526,6 +2687,9 @@
         -->
       <iso-code>SD</iso-code>
       <fips-code>SU</fips-code>
+      <timezones>
+        <timezone id="Africa/Khartoum" />
+      </timezones>
       <tz-hint>Africa/Khartoum</tz-hint>
       <city>
         <!-- Translators: this is the capital of Sudan.
@@ -2554,6 +2718,9 @@
         -->
       <iso-code>SZ</iso-code>
       <fips-code>WZ</fips-code>
+      <timezones>
+        <timezone id="Africa/Mbabane" />
+      </timezones>
       <tz-hint>Africa/Mbabane</tz-hint>
       <city>
         <!-- Translators: this is a city in Swaziland -->
@@ -2610,6 +2777,9 @@
         -->
       <iso-code>TZ</iso-code>
       <fips-code>TZ</fips-code>
+      <timezones>
+        <timezone id="Africa/Dar_es_Salaam" />
+      </timezones>
       <tz-hint>Africa/Dar_es_Salaam</tz-hint>
       <city>
         <!-- Translators: this is a city in Tanzania -->
@@ -2801,6 +2971,9 @@
         -->
       <iso-code>TG</iso-code>
       <fips-code>TO</fips-code>
+      <timezones>
+        <timezone id="Africa/Lome" />
+      </timezones>
       <tz-hint>Africa/Lome</tz-hint>
       <city>
         <!-- Translators: this is a city in Togo -->
@@ -2838,6 +3011,9 @@
       <_name>Tunisia</_name>
       <iso-code>TN</iso-code>
       <fips-code>TS</fips-code>
+      <timezones>
+        <timezone id="Africa/Tunis" />
+      </timezones>
       <tz-hint>Africa/Tunis</tz-hint>
       <city>
         <!-- Translators: this is a city in Tunisia -->
@@ -2993,6 +3169,9 @@
         -->
       <iso-code>UG</iso-code>
       <fips-code>UG</fips-code>
+      <timezones>
+        <timezone id="Africa/Kampala" />
+      </timezones>
       <tz-hint>Africa/Kampala</tz-hint>
       <city>
         <!-- Translators: this is a city in Uganda -->
@@ -3280,6 +3459,9 @@
       <_name>Western Sahara</_name>
       <iso-code>EH</iso-code>
       <fips-code>WI</fips-code>
+      <timezones>
+        <timezone id="Africa/El_Aaiun" />
+      </timezones>
       <tz-hint>Africa/El_Aaiun</tz-hint>
     </country>
     <country>
@@ -3292,6 +3474,9 @@
         -->
       <iso-code>ZM</iso-code>
       <fips-code>ZA</fips-code>
+      <timezones>
+        <timezone id="Africa/Lusaka" />
+      </timezones>
       <tz-hint>Africa/Lusaka</tz-hint>
       <city>
         <!-- Translators: this is the capital of Zambia -->
@@ -3309,6 +3494,9 @@
       <_name>Zimbabwe</_name>
       <iso-code>ZW</iso-code>
       <fips-code>ZI</fips-code>
+      <timezones>
+        <timezone id="Africa/Harare" />
+      </timezones>
       <tz-hint>Africa/Harare</tz-hint>
       <city>
         <!-- Translators: this is the capital of Zimbabwe -->
@@ -3329,6 +3517,82 @@
       <_name>Antarctica</_name>
       <iso-code>AQ</iso-code>
       <fips-code>AY</fips-code>
+      <timezones>
+        <timezone id="Antarctica/Palmer">
+          <!-- Translators: This is an American research station in
+               Antarctica, which keeps the same time as mainland Chile.
+               The string is only used in places where "Antarctica" is
+               already clear from context.
+            -->
+          <_name>Palmer Station (Chile Time)</_name>
+        </timezone>
+        <timezone id="Antarctica/Rothera">
+          <!-- Translators: This is a British research station in
+               Antarctica. The string is only used in places where
+               "Antarctica" is already clear from context.
+            -->
+          <_name>Rothera Research Station</_name>
+        </timezone>
+        <timezone id="Antarctica/Syowa">
+          <!-- Translators: This is a Japanese research station in
+               Antarctica. The string is only used in places where
+               "Antarctica" is already clear from context.
+            -->
+          <_name>Showa Station</_name>
+        </timezone>
+        <timezone id="Antarctica/Mawson">
+          <!-- Translators: This is an Australian research station in
+               Antarctica. The string is only used in places where
+               "Antarctica" is already clear from context.
+            -->
+          <_name>Mawson Station</_name>
+        </timezone>
+        <timezone id="Antarctica/Vostok">
+          <!-- Translators: This is a Russian research station in
+               Antarctica. The string is only used in places where
+               "Antarctica" is already clear from context.
+            -->
+          <_name>Vostok Station</_name>
+        </timezone>
+        <timezone id="Antarctica/Davis">
+          <!-- Translators: This is an Australian research station in
+               Antarctica. The string is only used in places where
+               "Antarctica" is already clear from context.
+            -->
+          <_name>Davis Station</_name>
+        </timezone>
+        <timezone id="Antarctica/Casey">
+          <!-- Translators: This is an Australian research station in
+               Antarctica, which keeps the same time as Western
+               Australia. The string is only used in places where
+               "Antarctica" is already clear from context.
+            -->
+          <_name>Casey Station (Western Australia Time)</_name>
+        </timezone>
+        <timezone id="Antarctica/DumontDUrville">
+          <!-- Translators: This is a French research station in
+               Antarctica. The string is only used in places where
+               "Antarctica" is already clear from context.
+            -->
+          <_name>Dumont d'Urville Station</_name>
+        </timezone>
+        <timezone id="Antarctica/McMurdo">
+          <!-- Translators: This is an American research station in
+               Antarctica, which keeps the same time as New Zealand. The
+               string is only used in places where "Antarctica" is
+               already clear from context.
+            -->
+          <_name>McMurdo Station (New Zealand Time)</_name>
+        </timezone>
+        <timezone id="Antarctica/South_Pole">
+          <!-- Translators: This is an American research station in
+               Antarctica, which keeps the same time as New Zealand. The
+               string is only used in places where "Antarctica" is
+               already clear from context.
+            -->
+          <_name>Amundsen-Scott South Pole Station (New Zealand Time)</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Antarctica/McMurdo</tz-hint>
     </country>
   </region>
@@ -3343,6 +3607,9 @@
         -->
       <iso-code>AF</iso-code>
       <fips-code>AF</fips-code>
+      <timezones>
+        <timezone id="Asia/Kabul" />
+      </timezones>
       <tz-hint>Asia/Kabul</tz-hint>
       <city>
         <!-- Translators: this is a city in Afghanistan -->
@@ -3381,6 +3648,9 @@
         -->
       <iso-code>AM</iso-code>
       <fips-code>AM</fips-code>
+      <timezones>
+        <timezone id="Asia/Yerevan" />
+      </timezones>
       <tz-hint>Asia/Yerevan</tz-hint>
       <city>
         <!-- Translators: this is a city in Armenia -->
@@ -3448,6 +3718,9 @@
         -->
       <iso-code>AZ</iso-code>
       <fips-code>AJ</fips-code>
+      <timezones>
+        <timezone id="Asia/Baku" />
+      </timezones>
       <tz-hint>Asia/Baku</tz-hint>
       <city>
         <!-- Translators: this is the capital of Azerbaijan.
@@ -3522,6 +3795,9 @@
         -->
       <iso-code>BD</iso-code>
       <fips-code>BG</fips-code>
+      <timezones>
+        <timezone id="Asia/Dhaka" />
+      </timezones>
       <tz-hint>Asia/Dhaka</tz-hint>
       <city>
         <!-- Translators: this is a city in Bangladesh.
@@ -3567,6 +3843,9 @@
         -->
       <iso-code>BT</iso-code>
       <fips-code>BT</fips-code>
+      <timezones>
+        <timezone id="Asia/Thimphu" />
+      </timezones>
       <tz-hint>Asia/Thimphu</tz-hint>
     </country>
     <country>
@@ -3574,6 +3853,9 @@
       <_name>Brunei</_name>
       <iso-code>BN</iso-code>
       <fips-code>BX</fips-code>
+      <timezones>
+        <timezone id="Asia/Brunei" />
+      </timezones>
       <tz-hint>Asia/Brunei</tz-hint>
       <city>
         <!-- Translators: this is the capital of Brunei -->
@@ -3591,6 +3873,9 @@
       <_name>Cambodia</_name>
       <iso-code>KH</iso-code>
       <fips-code>CB</fips-code>
+      <timezones>
+        <timezone id="Asia/Phnom_Penh" />
+      </timezones>
       <tz-hint>Asia/Phnom_Penh</tz-hint>
       <city>
         <!-- Translators: this is the capital of Cambodia.
@@ -3642,6 +3927,14 @@
         -->
       <iso-code>CN</iso-code>
       <fips-code>CH</fips-code>
+      <timezones>
+        <timezone id="Asia/Shanghai">
+          <obsoletes>Asia/Chongqing</obsoletes>
+          <obsoletes>Asia/Harbin</obsoletes>
+          <obsoletes>Asia/Kashgar</obsoletes>
+          <obsoletes>Asia/Urumqi</obsoletes>
+        </timezone>
+      </timezones>
       <tz-hint>Asia/Shanghai</tz-hint>
       <state>
         <!-- Translators: this is a state/province/territory in China -->
@@ -4133,6 +4426,9 @@
         -->
       <iso-code>GE</iso-code>
       <fips-code>GG</fips-code>
+      <timezones>
+        <timezone id="Asia/Tbilisi" />
+      </timezones>
       <tz-hint>Asia/Tbilisi</tz-hint>
     </country>
     <country>
@@ -4142,6 +4438,9 @@
       <_name>Hong Kong</_name>
       <iso-code>HK</iso-code>
       <fips-code>HK</fips-code>
+      <timezones>
+        <timezone id="Asia/Hong_Kong" />
+      </timezones>
       <tz-hint>Asia/Hong_Kong</tz-hint>
       <city>
         <!-- Translators: this is a city in Hong Kong -->
@@ -4174,6 +4473,9 @@
         -->
       <iso-code>IN</iso-code>
       <fips-code>IN</fips-code>
+      <timezones>
+        <timezone id="Asia/Kolkata" />
+      </timezones>
       <tz-hint>Asia/Kolkata</tz-hint>
       <city>
         <!-- Translators: this is a city in India -->
@@ -4402,6 +4704,9 @@
         -->
       <iso-code>JP</iso-code>
       <fips-code>JA</fips-code>
+      <timezones>
+        <timezone id="Asia/Tokyo" />
+      </timezones>
       <tz-hint>Asia/Tokyo</tz-hint>
       <city>
         <!-- Translators: this is a city in Japan -->
@@ -5450,6 +5755,25 @@
       <iso-code>KZ</iso-code>
       <fips-code>KZ</fips-code>
       <pref-lang>kaz</pref-lang>
+      <timezones>
+        <timezone id="Asia/Almaty">
+          <!-- Translators: This is the time zone used in the eastern
+               half of Kazakhstan. FIXME: is there an official name for
+               this zone?
+            -->
+          <_name>Eastern Kazakhstan</_name>
+          <obsoletes>Asia/Qyzylorda</obsoletes>
+        </timezone>
+        <timezone id="Asia/Aqtobe">
+          <!-- Translators: This is the time zone used in the western
+               half of Kazakhstan. FIXME: is there an official name for
+               this zone?
+            -->
+          <_name>Western Kazakhstan</_name>
+          <obsoletes>Asia/Aqtau</obsoletes>
+          <obsoletes>Asia/Oral</obsoletes>
+        </timezone>
+      </timezones>
       <tz-hint>Asia/Almaty</tz-hint>
       <city>
         <!-- Translators: this is a city in Kazakhstan -->
@@ -5574,6 +5898,9 @@
         -->
       <iso-code>KG</iso-code>
       <fips-code>KG</fips-code>
+      <timezones>
+        <timezone id="Asia/Bishkek" />
+      </timezones>
       <tz-hint>Asia/Bishkek</tz-hint>
       <city>
         <!-- Translators: this is the capital of Kyrgyzstan -->
@@ -5598,6 +5925,9 @@
         -->
       <iso-code>LA</iso-code>
       <fips-code>LA</fips-code>
+      <timezones>
+        <timezone id="Asia/Vientiane" />
+      </timezones>
       <tz-hint>Asia/Vientiane</tz-hint>
       <city>
         <!-- Translators: this is the capital of Laos.
@@ -5622,6 +5952,9 @@
       <_name>Macau</_name>
       <iso-code>MO</iso-code>
       <fips-code>MC</fips-code>
+      <timezones>
+        <timezone id="Asia/Macau" />
+      </timezones>
       <tz-hint>Asia/Macau</tz-hint>
       <city>
         <!-- Translators: this is the capital of Macau.
@@ -5662,6 +5995,11 @@
         -->
       <iso-code>MY</iso-code>
       <fips-code>MY</fips-code>
+      <timezones>
+        <timezone id="Asia/Kuala_Lumpur">
+          <obsoletes>Asia/Kuching</obsoletes>
+        </timezone>
+      </timezones>
       <tz-hint>Asia/Kuala_Lumpur</tz-hint>
       <city>
         <!-- Translators: this is a city in Malaysia -->
@@ -5869,6 +6207,9 @@
       <_name>Maldives</_name>
       <iso-code>MV</iso-code>
       <fips-code>MV</fips-code>
+      <timezones>
+        <timezone id="Indian/Maldives" />
+      </timezones>
       <tz-hint>Indian/Maldives</tz-hint>
       <city>
         <!-- Translators: this is the capital of Maldives.
@@ -5896,6 +6237,29 @@
         -->
       <iso-code>MN</iso-code>
       <fips-code>MG</fips-code>
+      <timezones>
+        <timezone id="Asia/Choibalsan">
+          <!-- Translators: This is the time zone used in the eastern part
+               of Mongolia. FIXME: Is there an official name for this
+               zone?
+            -->
+          <_name>Eastern Mongolia</_name>
+        </timezone>
+        <timezone id="Asia/Hovd">
+          <!-- Translators: This is the time zone used in the western part
+               of Mongolia. FIXME: Is there an official name for this
+               zone?
+            -->
+          <_name>Western Mongolia</_name>
+        </timezone>
+        <timezone id="Asia/Ulaanbaatar">
+          <!-- Translators: This is the time zone used in the central part
+               of Mongolia. FIXME: Is there an official name for this
+               zone?
+            -->
+          <_name>Central Mongolia</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Asia/Ulaanbaatar</tz-hint>
       <city>
         <!-- Translators: this is a city in Mongolia.
@@ -5939,6 +6303,9 @@
         -->
       <iso-code>MM</iso-code>
       <fips-code>BM</fips-code>
+      <timezones>
+        <timezone id="Asia/Rangoon" />
+      </timezones>
       <tz-hint>Asia/Rangoon</tz-hint>
       <city>
         <!-- Translators: this is the capital of Myanmar.
@@ -5959,6 +6326,9 @@
       <_name>Nepal</_name>
       <iso-code>NP</iso-code>
       <fips-code>NP</fips-code>
+      <timezones>
+        <timezone id="Asia/Katmandu" />
+      </timezones>
       <tz-hint>Asia/Katmandu</tz-hint>
       <city>
         <!-- Translators: this is the capital of Nepal.
@@ -5985,6 +6355,9 @@
         -->
       <iso-code>KP</iso-code>
       <fips-code>KN</fips-code>
+      <timezones>
+        <timezone id="Asia/Pyongyang" />
+      </timezones>
       <tz-hint>Asia/Pyongyang</tz-hint>
     </country>
     <country>
@@ -5996,6 +6369,9 @@
         -->
       <iso-code>PK</iso-code>
       <fips-code>PK</fips-code>
+      <timezones>
+        <timezone id="Asia/Karachi" />
+      </timezones>
       <tz-hint>Asia/Karachi</tz-hint>
       <city>
         <!-- Translators: this is the capital of Pakistan -->
@@ -6053,6 +6429,9 @@
       <_name>Philippines</_name>
       <iso-code>PH</iso-code>
       <fips-code>RP</fips-code>
+      <timezones>
+        <timezone id="Asia/Manila" />
+      </timezones>
       <tz-hint>Asia/Manila</tz-hint>
       <city>
         <!-- Translators: this is a city in Philippines -->
@@ -6144,6 +6523,9 @@
         -->
       <iso-code>SG</iso-code>
       <fips-code>SN</fips-code>
+      <timezones>
+        <timezone id="Asia/Singapore" />
+      </timezones>
       <tz-hint>Asia/Singapore</tz-hint>
       <city>
         <!-- Translators: this is the capital of Singapore -->
@@ -6174,6 +6556,9 @@
         -->
       <iso-code>KR</iso-code>
       <fips-code>KS</fips-code>
+      <timezones>
+        <timezone id="Asia/Seoul" />
+      </timezones>
       <tz-hint>Asia/Seoul</tz-hint>
       <city>
         <!-- Translators: this is a city in South Korea -->
@@ -6338,6 +6723,9 @@
       <_name>Sri Lanka</_name>
       <iso-code>LK</iso-code>
       <fips-code>CE</fips-code>
+      <timezones>
+        <timezone id="Asia/Colombo" />
+      </timezones>
       <tz-hint>Asia/Colombo</tz-hint>
       <city>
         <!-- Translators: this is the capital of Sri Lanka -->
@@ -6377,6 +6765,9 @@
       <_name>Taiwan</_name>
       <iso-code>TW</iso-code>
       <fips-code>TW</fips-code>
+      <timezones>
+        <timezone id="Asia/Taipei" />
+      </timezones>
       <tz-hint>Asia/Taipei</tz-hint>
       <city>
         <!-- Translators: this is a city in Taiwan.
@@ -6436,6 +6827,9 @@
         -->
       <iso-code>TJ</iso-code>
       <fips-code>TI</fips-code>
+      <timezones>
+        <timezone id="Asia/Dushanbe" />
+      </timezones>
       <tz-hint>Asia/Dushanbe</tz-hint>
       <city>
         <!-- Translators: this is the capital of Tajikistan -->
@@ -6471,6 +6865,9 @@
         -->
       <iso-code>TH</iso-code>
       <fips-code>TH</fips-code>
+      <timezones>
+        <timezone id="Asia/Bangkok" />
+      </timezones>
       <tz-hint>Asia/Bangkok</tz-hint>
       <city>
         <!-- Translators: this is a city in Thailand.
@@ -6790,6 +7187,9 @@
         -->
       <iso-code>TM</iso-code>
       <fips-code>TX</fips-code>
+      <timezones>
+        <timezone id="Asia/Ashgabat" />
+      </timezones>
       <tz-hint>Asia/Ashgabat</tz-hint>
       <city>
         <!-- Translators: this is the capital of Turkmenistan.
@@ -6819,6 +7219,11 @@
         -->
       <iso-code>UZ</iso-code>
       <fips-code>UZ</fips-code>
+      <timezones>
+        <timezone id="Asia/Tashkent">
+          <obsoletes>Asia/Samarkand</obsoletes>
+        </timezone>
+      </timezones>
       <tz-hint>Asia/Tashkent</tz-hint>
       <city>
         <!-- Translators: this is a city in Uzbekistan -->
@@ -6894,6 +7299,9 @@
         -->
       <iso-code>VN</iso-code>
       <fips-code>VM</fips-code>
+      <timezones>
+        <timezone id="Asia/Ho_Chi_Minh" />
+      </timezones>
       <tz-hint>Asia/Ho_Chi_Minh</tz-hint>
       <city>
         <!-- Translators: this is a city in Viet Nam -->
@@ -7031,6 +7439,9 @@
       <_name>Anguilla</_name>
       <iso-code>AI</iso-code>
       <fips-code>AV</fips-code>
+      <timezones>
+        <timezone id="America/Anguilla" />
+      </timezones>
       <tz-hint>America/Anguilla</tz-hint>
       <city>
         <!-- Translators: this is the capital of Anguilla -->
@@ -7048,6 +7459,9 @@
       <_name>Antigua and Barbuda</_name>
       <iso-code>AG</iso-code>
       <fips-code>AC</fips-code>
+      <timezones>
+        <timezone id="America/Antigua" />
+      </timezones>
       <tz-hint>America/Antigua</tz-hint>
       <city>
         <!-- Translators: this is a city in Antigua and Barbuda -->
@@ -7075,6 +7489,9 @@
       <_name>Barbados</_name>
       <iso-code>BB</iso-code>
       <fips-code>BB</fips-code>
+      <timezones>
+        <timezone id="America/Barbados" />
+      </timezones>
       <tz-hint>America/Barbados</tz-hint>
       <city>
         <!-- Translators: this is the capital of Barbados -->
@@ -7104,6 +7521,9 @@
       <_name>Bermuda</_name>
       <iso-code>BM</iso-code>
       <fips-code>BD</fips-code>
+      <timezones>
+        <timezone id="Atlantic/Bermuda" />
+      </timezones>
       <tz-hint>Atlantic/Bermuda</tz-hint>
       <city>
         <!-- Translators: this is the capital of Bermuda -->
@@ -7133,6 +7553,9 @@
       <_name>Dominica</_name>
       <iso-code>DM</iso-code>
       <fips-code>DO</fips-code>
+      <timezones>
+        <timezone id="America/Dominica" />
+      </timezones>
       <tz-hint>America/Dominica</tz-hint>
       <city>
         <!-- Translators: this is a city in Dominica -->
@@ -7181,6 +7604,34 @@
       <iso-code>GL</iso-code>
       <fips-code>GL</fips-code>
       <pref-lang>dan</pref-lang>
+      <timezones>
+        <timezone id="America/Danmarkshavn">
+          <!-- Translators: This is the timezone around Danmarkshavn
+               station in Greenland. The string is only used in places
+               where "Greenland" is already clear from context.
+            -->
+          <_name>Danmarkshavn</_name>
+        </timezone>
+        <timezone id="America/Godthab">
+          <!-- Translators: This is the primary timezone for Greenland,
+               although sources seem to point towards calling the area
+               "Western Greenland" rathern than just "Greenland".
+            -->
+          <_name>Western Greenland</_name>
+        </timezone>
+        <timezone id="America/Scoresbysund">
+          <!-- Translators: This is the timezone around Scoresbysund /
+               Ittoqqortoormiit on the east coast of Greenland.
+            -->
+          <_name>Eastern Greenland</_name>
+        </timezone>
+        <timezone id="America/Thule">
+          <!-- Translators: This is the timezone at the Thule US Air Force
+               Base on the west coast of Greenland.
+            -->
+          <_name>Thule AFB</_name>
+        </timezone>
+      </timezones>
       <tz-hint>America/Godthab</tz-hint>
       <city>
         <!-- Translators: this is a city in Greenland.
@@ -7277,6 +7728,11 @@
       <_name>Puerto Rico</_name>
       <iso-code>PR</iso-code>
       <fips-code>US72</fips-code>
+      <timezones>
+        <timezone id="America/Puerto_Rico">
+          <_name>Atlantic Time</_name>
+        </timezone>
+      </timezones>
       <tz-hint>America/Puerto_Rico</tz-hint>
       <city>
         <!-- Translators: this is a city in Puerto Rico -->
@@ -7330,6 +7786,9 @@
       <_name>Saint BarthÃlemy</_name>
       <iso-code>BL</iso-code>
       <fips-code>TB</fips-code>
+      <timezones>
+        <timezone id="America/St_Barthelemy" />
+      </timezones>
       <tz-hint>America/St_Barthelemy</tz-hint>
     </country>
     <country>
@@ -7341,6 +7800,9 @@
         -->
       <iso-code>SH</iso-code>
       <fips-code>SH</fips-code>
+      <timezones>
+        <timezone id="Atlantic/St_Helena" />
+      </timezones>
       <tz-hint>Atlantic/St_Helena</tz-hint>
       <city>
         <!-- Translators: this is a city in Saint Helena -->
@@ -7358,6 +7820,9 @@
       <_name>Saint Kitts and Nevis</_name>
       <iso-code>KN</iso-code>
       <fips-code>SC</fips-code>
+      <timezones>
+        <timezone id="America/St_Kitts" />
+      </timezones>
       <tz-hint>America/St_Kitts</tz-hint>
       <city>
         <!-- Translators: this is the capital of Saint Kitts and Nevis -->
@@ -7407,6 +7872,11 @@
       <_name>United States Virgin Islands</_name>
       <iso-code>VI</iso-code>
       <fips-code>US78</fips-code>
+      <timezones>
+        <timezone id="America/St_Thomas">
+          <_name>Atlantic Time</_name>
+        </timezone>
+      </timezones>
       <tz-hint>America/St_Thomas</tz-hint>
       <city>
         <!-- Translators: this is a city in United States Virgin Islands
@@ -7442,6 +7912,9 @@
       <_name>American Samoa</_name>
       <iso-code>AS</iso-code>
       <fips-code>US60</fips-code>
+      <timezones>
+        <timezone id="Pacific/Pago_Pago" />
+      </timezones>
       <tz-hint>Pacific/Pago_Pago</tz-hint>
       <city>
         <!-- Translators: this is a city in American Samoa -->
@@ -7463,6 +7936,98 @@
         -->
       <iso-code>AU</iso-code>
       <fips-code>AS</fips-code>
+      <timezones>
+        <timezone id="Australia/Perth">
+          <!-- Translators: This is the time zone used in Western
+               Australia. The string is only used in places where
+               "Australia" is already clear from context.
+            -->
+          <_name>Western Time</_name>
+        </timezone>
+        <timezone id="Australia/Eucla">
+          <!-- Translators: This is the commonly-used name for an
+               unofficial time zone used in part of southwestern
+               Australia. The string is only used in places where
+               "Australia" is already clear from context.
+            -->
+          <_name>Central Western Time</_name>
+        </timezone>
+        <timezone id="Australia/Adelaide">
+          <!-- Translators: This is the time zone used in Central
+               Australia. This string is specifically for the time zone
+               as implemented in the state of South Australia, and is
+               only used in places where "Australia" is already clear
+               from context.
+            -->
+          <_name>Central Time (South Australia)</_name>
+        </timezone>
+        <timezone id="Australia/Broken_Hill">
+          <!-- Translators: This is the time zone used in Central
+               Australia. This string is specifically for the time zone
+               as implemented in Yancowinna county in the state of New
+               South Wales (NSW), which uses Central Time even though
+               the rest of the state uses Eastern Time. This string is
+               only used in places where "Australia" is already clear
+               from context.
+            -->
+          <_name>Central Time (Yancowinna, NSW)</_name>
+        </timezone>
+        <timezone id="Australia/Darwin">
+          <!-- Translators: This is the time zone used in Central
+               Australia. This string is specifically for the time zone
+               as implemented in the Northern Territory, which does not
+               use Summer Time. This string is only used in places where
+               "Australia" is already clear from context.
+            -->
+          <_name>Central Time (Northern Territory)</_name>
+        </timezone>
+        <timezone id="Australia/Hobart">
+          <!-- Translators: This is the time zone used in Eastern
+               Australia. This string is specifically for the time zone
+               as implemented in the state of Tasmania, and is only used
+               in places where "Australia" is already clear from
+               context.
+            -->
+          <_name>Eastern Time (Tasmania)</_name>
+          <obsoletes>Australia/Currie</obsoletes>
+        </timezone>
+        <timezone id="Australia/Melbourne">
+          <!-- Translators: This is the time zone used in Eastern
+               Australia. This string is specifically for the time zone
+               as implemented in the state of Victoria, and is only used
+               in places where "Australia" is already clear from
+               context.
+            -->
+          <_name>Eastern Time (Victoria)</_name>
+        </timezone>
+        <timezone id="Australia/Sydney">
+          <!-- Translators: This is the time zone used in Eastern
+               Australia. This string is specifically for the time zone
+               as implemented in the state of New South Wales, and is
+               only used in places where "Australia" is already clear
+               from context.
+            -->
+          <_name>Eastern Time (New South Wales)</_name>
+        </timezone>
+        <timezone id="Australia/Brisbane">
+          <!-- Translators: This is the time zone used in Eastern
+               Australia. This string is specifically for the time zone
+               as implemented in the state of Queensland, which does not
+               use Summer Time. This string is only used in places where
+               "Australia" is already clear from context.
+            -->
+          <_name>Eastern Time (Queensland)</_name>
+          <obsoletes>Australia/Lindeman</obsoletes>
+        </timezone>
+        <timezone id="Australia/Lord_Howe">
+          <!-- Translators: This is the time zone used on Lord Howe
+               Island, off the east coast of Australia. This string is
+               only used in places where "Australia" is already clear
+               from context.
+            -->
+          <_name>Lord Howe Island</_name>
+        </timezone>
+      </timezones>
       <state>
         <!-- Translators: this is a state/province/territory in
              Australia
@@ -7861,6 +8426,9 @@
         -->
       <iso-code>IO</iso-code>
       <fips-code>IO</fips-code>
+      <timezones>
+        <timezone id="Indian/Chagos" />
+      </timezones>
       <tz-hint>Indian/Chagos</tz-hint>
     </country>
     <country>
@@ -7875,6 +8443,9 @@
         -->
       <iso-code>CX</iso-code>
       <fips-code>KT</fips-code>
+      <timezones>
+        <timezone id="Indian/Christmas" />
+      </timezones>
       <tz-hint>Indian/Christmas</tz-hint>
       <city>
         <!-- Translators: this is a city in Christmas Island -->
@@ -7905,6 +8476,9 @@
       <_name>Cocos (Keeling) Islands</_name>
       <iso-code>CC</iso-code>
       <fips-code>CK</fips-code>
+      <timezones>
+        <timezone id="Indian/Cocos" />
+      </timezones>
       <tz-hint>Indian/Cocos</tz-hint>
       <city>
         <!-- Translators: this is a city in Cocos (Keeling) Islands -->
@@ -7923,6 +8497,9 @@
       <_name>Cook Islands</_name>
       <iso-code>CK</iso-code>
       <fips-code>CW</fips-code>
+      <timezones>
+        <timezone id="Pacific/Rarotonga" />
+      </timezones>
       <tz-hint>Pacific/Rarotonga</tz-hint>
       <city>
         <!-- Translators: this is the capital of Cook Islands -->
@@ -7940,6 +8517,9 @@
       <_name>Fiji</_name>
       <iso-code>FJ</iso-code>
       <fips-code>FJ</fips-code>
+      <timezones>
+        <timezone id="Pacific/Fiji" />
+      </timezones>
       <tz-hint>Pacific/Fiji</tz-hint>
       <city>
         <!-- Translators: this is a city in Fiji -->
@@ -7969,6 +8549,32 @@
       <_name>French Polynesia</_name>
       <iso-code>PF</iso-code>
       <fips-code>FP</fips-code>
+      <timezones>
+        <timezone id="Pacific/Tahiti">
+          <!-- Translators: This refers to the time zone in the Society
+               Islands of French Polynesia (including in particular the
+               island of Tahiti). This string is only used in places where
+               "French Polynesia" is already clear from context.
+            -->
+          <_name>Tahiti / Society Islands</_name>
+        </timezone>
+        <timezone id="Pacific/Marquesas">
+          <!-- Translators: This refers to the time zone in the
+               Marquesas Islands of French Polynesia. This string is
+               only used in places where "French Polynesia" is already
+               clear from context.
+            -->
+          <_name>Marquesas Islands</_name>
+        </timezone>
+        <timezone id="Pacific/Gambier">
+          <!-- Translators: This refers to the time zone in the Gambier
+               Islands of French Polynesia. This string is only used in
+               places where "French Polynesia" is already clear from
+               context.
+            -->
+          <_name>Gambier Islands</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Pacific/Tahiti</tz-hint>
       <city>
         <!-- Translators: this is the capital of French Polynesia -->
@@ -7992,6 +8598,9 @@
         -->
       <iso-code>GU</iso-code>
       <fips-code>US66</fips-code>
+      <timezones>
+        <timezone id="Pacific/Guam" />
+      </timezones>
       <tz-hint>Pacific/Guam</tz-hint>
       <city>
         <!-- Translators: this is a city in Guam -->
@@ -8030,6 +8639,30 @@
         -->
       <iso-code>ID</iso-code>
       <fips-code>ID</fips-code>
+      <timezones>
+        <timezone id="Asia/Jakarta">
+          <!-- Translators: this is the timezone on the western islands of
+               Indonesia. The name in Indonesian is "Waktu Indonesia
+               Bagian Barat".
+            -->
+          <_name>Western Indonesia Time</_name>
+          <obsoletes>Asia/Pontianak</obsoletes>
+        </timezone>
+        <timezone id="Asia/Makassar">
+          <!-- Translators: this is the timezone on the central islands of
+               Indonesia. The name in Indonesian is "Waktu Indonesia
+               Bagian Tengah".
+            -->
+          <_name>Central Indonesia Time</_name>
+        </timezone>
+        <timezone id="Asia/Jayapura">
+          <!-- Translators: this is the timezone on the eastern islands of
+               Indonesia. The name in Indonesian is "Waktu Indonesia
+               Bagian Timur".
+            -->
+          <_name>Eastern Indonesia Time</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Asia/Jakarta</tz-hint>
       <city>
         <!-- Translators: this is the capital of Indonesia -->
@@ -8092,6 +8725,32 @@
         -->
       <iso-code>KI</iso-code>
       <fips-code>KR</fips-code>
+      <timezones>
+        <timezone id="Pacific/Tarawa">
+          <!-- Translators: This is the time zone in the Gilbert
+               Islands, one of the three main island groups of Kiribati.
+               This string is only used in places where "Kiribati" is
+               already clear from context.
+            -->
+          <_name>Gilbert Islands</_name>
+        </timezone>
+        <timezone id="Pacific/Enderbury">
+          <!-- Translators: This is the time zone in the Phoenix
+               Islands, one of the three main island groups of Kiribati.
+               This string is only used in places where "Kiribati" is
+               already clear from context.
+            -->
+          <_name>Phoenix Islands</_name>
+        </timezone>
+        <timezone id="Pacific/Kiritimati">
+          <!-- Translators: This is the time zone in the Line Islands,
+               one of the three main island groups of Kiribati. This
+               string is only used in places where "Kiribati" is already
+               clear from context.
+            -->
+          <_name>Line Islands</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Pacific/Tarawa</tz-hint>
       <city>
         <!-- Translators: this is a city in Kiribati -->
@@ -8114,6 +8773,11 @@
       <iso-code>MH</iso-code>
       <fips-code>RM</fips-code>
       <fips-code>US68</fips-code>
+      <timezones>
+        <timezone id="Pacific/Majuro">
+          <obsoletes>Pacific/Kwajalein</obsoletes>
+        </timezone>
+      </timezones>
       <tz-hint>Pacific/Majuro</tz-hint>
       <city>
         <!-- Translators: this is the capital of Marshall Islands -->
@@ -8141,6 +8805,25 @@
       <iso-code>FM</iso-code>
       <fips-code>FM</fips-code>
       <fips-code>US64</fips-code>
+      <timezones>
+        <timezone id="Pacific/Ponape">
+          <!-- Translators: This is one of two time zones in the
+               Federated States of Micronesia, including the islands of
+               Pohnpei and Kosrae. The string is only used in places
+               where "Micronesia" is already clear from context.
+            -->
+          <_name>Pohnpei / Kosrae</_name>
+          <obsoletes>Pacific/Kosrae</obsoletes>
+        </timezone>
+        <timezone id="Pacific/Truk">
+          <!-- Translators: This is one of two time zones in the Federated
+               States of Micronesia, including the islands of Yap and
+               Chuuk. The string is only used in places where "Micronesia"
+               is already clear from context.
+            -->
+          <_name>Yap / Chuuk</_name>
+        </timezone>
+      </timezones>
       <city>
         <!-- Translators: this is a city in Micronesia, Federated
              States of
@@ -8212,6 +8895,9 @@
       <_name>Nauru</_name>
       <iso-code>NR</iso-code>
       <fips-code>NR</fips-code>
+      <timezones>
+        <timezone id="Pacific/Nauru" />
+      </timezones>
       <tz-hint>Pacific/Nauru</tz-hint>
     </country>
     <country>
@@ -8221,6 +8907,9 @@
       <_name>New Caledonia</_name>
       <iso-code>NC</iso-code>
       <fips-code>NC</fips-code>
+      <timezones>
+        <timezone id="Pacific/Noumea" />
+      </timezones>
       <tz-hint>Pacific/Noumea</tz-hint>
       <city>
         <!-- Translators: this is a city in New Caledonia -->
@@ -8248,6 +8937,24 @@
       <_name>New Zealand</_name>
       <iso-code>NZ</iso-code>
       <fips-code>NZ</fips-code>
+      <timezones>
+        <timezone id="Pacific/Auckland">
+          <!-- Translators: This refers to the "mainland" of New Zealand
+               (ie, North Island and South Island), to distinguish it from
+               the Chatham Islands. The string is only used in places
+               where "New Zealand" is already clear from context. FIXME:
+               is there a better name for this? "Mainland" seems odd in
+               reference to an island nation...
+            -->
+          <_name>Mainland New Zealand</_name>
+        </timezone>
+        <timezone id="Pacific/Chatham">
+          <!-- Translators: This refers to the time zone in the Chatham
+               Islands of New Zealand.
+            -->
+          <_name>Chatham Islands</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Pacific/Auckland</tz-hint>
       <city>
         <!-- Translators: this is a city in New Zealand -->
@@ -8285,6 +8992,9 @@
       <_name>Niue</_name>
       <iso-code>NU</iso-code>
       <fips-code>NE</fips-code>
+      <timezones>
+        <timezone id="Pacific/Niue" />
+      </timezones>
       <tz-hint>Pacific/Niue</tz-hint>
       <city>
         <!-- Translators: this is the capital of Niue -->
@@ -8302,6 +9012,9 @@
       <_name>Norfolk Island</_name>
       <iso-code>NF</iso-code>
       <fips-code>NF</fips-code>
+      <timezones>
+        <timezone id="Pacific/Norfolk" />
+      </timezones>
       <tz-hint>Pacific/Norfolk</tz-hint>
       <city>
         <!-- Translators: this is a city in Norfolk Island -->
@@ -8322,6 +9035,9 @@
       <_name>Northern Mariana Islands</_name>
       <iso-code>MP</iso-code>
       <fips-code>US69</fips-code>
+      <timezones>
+        <timezone id="Pacific/Saipan" />
+      </timezones>
       <tz-hint>Pacific/Saipan</tz-hint>
       <city>
         <!-- Translators: this is a city in Northern Mariana Islands -->
@@ -8344,6 +9060,9 @@
       <_name>Palau</_name>
       <iso-code>PW</iso-code>
       <fips-code>PS|US70</fips-code>
+      <timezones>
+        <timezone id="Pacific/Palau" />
+      </timezones>
       <tz-hint>Pacific/Palau</tz-hint>
       <city>
         <!-- Translators: this is the capital of Palau -->
@@ -8380,6 +9099,9 @@
         -->
       <iso-code>PG</iso-code>
       <fips-code>PP</fips-code>
+      <timezones>
+        <timezone id="Pacific/Port_Moresby" />
+      </timezones>
       <tz-hint>Pacific/Port_Moresby</tz-hint>
       <city>
         <!-- Translators: this is a city in Papua New Guinea -->
@@ -8421,6 +9143,9 @@
         -->
       <iso-code>PN</iso-code>
       <fips-code>PC</fips-code>
+      <timezones>
+        <timezone id="Pacific/Pitcairn" />
+      </timezones>
       <tz-hint>Pacific/Pitcairn</tz-hint>
     </country>
     <country>
@@ -8430,6 +9155,9 @@
       <_name>Samoa</_name>
       <iso-code>WS</iso-code>
       <fips-code>WS</fips-code>
+      <timezones>
+        <timezone id="Pacific/Apia" />
+      </timezones>
       <tz-hint>Pacific/Apia</tz-hint>
       <city>
         <!-- Translators: this is the capital of Samoa -->
@@ -8457,6 +9185,9 @@
       <_name>Solomon Islands</_name>
       <iso-code>SB</iso-code>
       <fips-code>BP</fips-code>
+      <timezones>
+        <timezone id="Pacific/Guadalcanal" />
+      </timezones>
       <tz-hint>Pacific/Guadalcanal</tz-hint>
       <city>
         <!-- Translators: this is the capital of Solomon Islands -->
@@ -8478,6 +9209,9 @@
         -->
       <iso-code>TL</iso-code>
       <fips-code>TT</fips-code>
+      <timezones>
+        <timezone id="Asia/Dili" />
+      </timezones>
       <tz-hint>Asia/Dili</tz-hint>
     </country>
     <country>
@@ -8485,6 +9219,9 @@
       <_name>Tokelau</_name>
       <iso-code>TK</iso-code>
       <fips-code>TL</fips-code>
+      <timezones>
+        <timezone id="Pacific/Fakaofo" />
+      </timezones>
       <tz-hint>Pacific/Fakaofo</tz-hint>
     </country>
     <country>
@@ -8492,6 +9229,9 @@
       <_name>Tonga</_name>
       <iso-code>TO</iso-code>
       <fips-code>TN</fips-code>
+      <timezones>
+        <timezone id="Pacific/Tongatapu" />
+      </timezones>
       <tz-hint>Pacific/Tongatapu</tz-hint>
       <city>
         <!-- Translators: this is a city in Tonga -->
@@ -8519,6 +9259,9 @@
       <_name>Tuvalu</_name>
       <iso-code>TV</iso-code>
       <fips-code>TV</fips-code>
+      <timezones>
+        <timezone id="Pacific/Funafuti" />
+      </timezones>
       <tz-hint>Pacific/Funafuti</tz-hint>
       <city>
         <!-- Translators: this is the capital of Tuvalu -->
@@ -8539,6 +9282,35 @@
       <_name>United States Minor Outlying Islands</_name>
       <iso-code>UM</iso-code>
       <fips-code>US74</fips-code>
+      <timezones>
+        <timezone id="Pacific/Johnston">
+          <!-- Translators: This is the time zone for the Johnston Atoll
+               in the United States Minor Outlying Islands, which keeps
+               the same time as the US state of Hawaii. The string is only
+               used in places where "US Minor Outlying Islands" is already
+               clear from context.
+            -->
+          <_name>Johnston Atoll (Hawaii Time)</_name>
+        </timezone>
+        <timezone id="Pacific/Midway">
+          <!-- Translators: This is the time zone for the Midway Atoll in
+               the United States Minor Outlying Islands, which uses the
+               same time as American Samoa (which is in fact also the same
+               time zone as (non-American) Samoa). The string is only used
+               in places where "US Minor Outlying Islands" is already
+               clear from context.
+            -->
+          <_name>Midway Atoll (Samoa Time)</_name>
+        </timezone>
+        <timezone id="Pacific/Wake">
+          <!-- Translators: This is the time zone for Wake Island in the
+               United States Minor Outlying Islands. The string is only
+               used in places where "US Minor Outlying Islands" is already
+               clear from context.
+            -->
+          <_name>Wake Island</_name>
+        </timezone>
+      </timezones>
       <city>
         <!-- Translators: this is a city in United States Minor
              Outlying Islands
@@ -8557,6 +9329,9 @@
       <_name>Vanuatu</_name>
       <iso-code>VU</iso-code>
       <fips-code>NH</fips-code>
+      <timezones>
+        <timezone id="Pacific/Efate" />
+      </timezones>
       <tz-hint>Pacific/Efate</tz-hint>
       <city>
         <!-- Translators: this is the capital of Vanuatu -->
@@ -8580,6 +9355,9 @@
         -->
       <iso-code>WF</iso-code>
       <fips-code>WF</fips-code>
+      <timezones>
+        <timezone id="Pacific/Wallis" />
+      </timezones>
       <tz-hint>Pacific/Wallis</tz-hint>
     </country>
   </region>
@@ -8600,6 +9378,20 @@
         -->
       <iso-code>AR</iso-code>
       <fips-code>AR</fips-code>
+      <timezones>
+        <timezone id="America/Argentina/Buenos_Aires">
+          <obsoletes>America/Argentina/Catamarca</obsoletes>
+          <obsoletes>America/Argentina/Cordoba</obsoletes>
+          <obsoletes>America/Argentina/Jujuy</obsoletes>
+          <obsoletes>America/Argentina/La_Rioja</obsoletes>
+          <obsoletes>America/Argentina/Mendoza</obsoletes>
+          <obsoletes>America/Argentina/Rio_Gallegos</obsoletes>
+          <obsoletes>America/Argentina/San_Juan</obsoletes>
+          <obsoletes>America/Argentina/San_Luis</obsoletes>
+          <obsoletes>America/Argentina/Tucuman</obsoletes>
+          <obsoletes>America/Argentina/Ushuaia</obsoletes>
+        </timezone>
+      </timezones>
       <tz-hint>America/Argentina/Buenos_Aires</tz-hint>
       <city>
         <!-- Translators: this is the capital of Argentina -->
@@ -8819,6 +9611,9 @@
       <_name>Aruba</_name>
       <iso-code>AW</iso-code>
       <fips-code>AA</fips-code>
+      <timezones>
+        <timezone id="America/Aruba" />
+      </timezones>
       <tz-hint>America/Aruba</tz-hint>
       <city>
         <!-- Translators: this is a city in Aruba -->
@@ -8846,6 +9641,9 @@
       <_name>Bahamas</_name>
       <iso-code>BS</iso-code>
       <fips-code>BF</fips-code>
+      <timezones>
+        <timezone id="America/Nassau" />
+      </timezones>
       <tz-hint>America/Nassau</tz-hint>
       <city>
         <!-- Translators: this is a city in Bahamas -->
@@ -8887,6 +9685,9 @@
         -->
       <iso-code>BZ</iso-code>
       <fips-code>BH</fips-code>
+      <timezones>
+        <timezone id="America/Belize" />
+      </timezones>
       <tz-hint>America/Belize</tz-hint>
       <city>
         <!-- Translators: this is a city in Belize -->
@@ -8904,6 +9705,9 @@
       <_name>Bolivia</_name>
       <iso-code>BO</iso-code>
       <fips-code>BL</fips-code>
+      <timezones>
+        <timezone id="America/La_Paz" />
+      </timezones>
       <tz-hint>America/La_Paz</tz-hint>
       <city>
         <!-- Translators: this is a city in Bolivia -->
@@ -9164,6 +9968,145 @@
         -->
       <iso-code>BR</iso-code>
       <fips-code>BR</fips-code>
+      <timezones>
+        <timezone id="America/Araguaina">
+          <!-- Translators: This represents the time zone in the Brazilian
+               state of Tocantins. See the comment on "BrasÃlia Time" for
+               more details. This string is only used in places where
+               "Brazil" is already clear from context.
+            -->
+          <_name>Tocantins</_name>
+        </timezone>
+        <timezone id="America/Bahia">
+          <!-- Translators: This represents the time zone in the Brazilian
+               state of Bahia. See the comment on "BrasÃlia Time" for more
+               details. This string is only used in places where "Brazil"
+               is already clear from context.
+            -->
+          <_name>Bahia</_name>
+        </timezone>
+        <timezone id="America/Belem">
+          <!-- Translators: This represents the time zone in the Brazilian
+               state of Amapà and the eastern part of ParÃ. See the
+               comment on "BrasÃlia Time" for more details. This string is
+               only used in places where "Brazil" is already clear from
+               context.
+            -->
+          <_name>Amapà / East ParÃ</_name>
+        </timezone>
+        <timezone id="America/Boa_Vista">
+          <!-- Translators: This represents the time zone in the Brazilian
+               state of Roraima. See the comment on "BrasÃlia Time" for
+               more details. This string is only used in places where
+               "Brazil" is already clear from context.
+            -->
+          <_name>Roraima</_name>
+        </timezone>
+        <timezone id="America/Campo_Grande">
+          <!-- Translators: This represents the time zone in the Brazilian
+               state of Mato Grosso do Sul. See the comment on "BrasÃlia
+               Time" for more details. This string is only used in places
+               where "Brazil" is already clear from context.
+            -->
+          <_name>Mato Grosso do Sul</_name>
+        </timezone>
+        <timezone id="America/Cuiaba">
+          <!-- Translators: This represents the time zone in the Brazilian
+               state of Mato Grosso. See the comment on "BrasÃlia Time"
+               for more details. This string is only used in places where
+               "Brazil" is already clear from context.
+            -->
+          <_name>Mato Grosso</_name>
+        </timezone>
+        <timezone id="America/Eirunepe">
+          <!-- Translators: This represents the time zone in the western
+               part of the Brazilian state of Amazonas. See the comment on
+               "BrasÃlia Time" for more details. This string is only used
+               in places where "Brazil" is already clear from context.
+            -->
+          <_name>West Amazonas</_name>
+        </timezone>
+        <timezone id="America/Fortaleza">
+          <!-- Translators: This represents the time zone in the Brazilian
+               states of CearÃ, MaranhÃo, ParaÃba, PiauÃ, and Rio Grande
+               do Norte. See the comment on "BrasÃlia Time" for more
+               details. This string is only used in places where "Brazil"
+               is already clear from context.
+            -->
+          <_name>CearÃ, MaranhÃo, ParaÃba, PiauÃ, Rio Grande do Norte</_name>
+        </timezone>
+        <timezone id="America/Maceio">
+          <!-- Translators: This represents the time zone in the Brazilian
+               states of Alagoas and Sergipe. See the comment on "BrasÃlia
+               Time" for more details. This string is only used in places
+               where "Brazil" is already clear from context.
+            -->
+          <_name>Alagoas, Sergipe</_name>
+        </timezone>
+        <timezone id="America/Manaus">
+          <!-- Translators: This represents the time zone in the eastern
+               part of the Brazilian state of Amazonas. See the comment on
+               "BrasÃlia Time" for more details. This string is only used
+               in places where "Brazil" is already clear from context.
+            -->
+          <_name>East Amazonas</_name>
+        </timezone>
+        <timezone id="America/Noronha">
+          <!-- Translators: This represents the time zone on the Brazilian
+               island of Fernando de Noronha. See the comment on "BrasÃlia
+               Time" for more details. This string is only used in places
+               where "Brazil" is already clear from context.
+            -->
+          <_name>Fernando de Noronha</_name>
+        </timezone>
+        <timezone id="America/Porto_Velho">
+          <!-- Translators: This represents the time zone in the Brazilian
+               state of RondÃnia and the western part of ParÃ. See the
+               comment on "BrasÃlia Time" for more details. This string is
+               only used in places where "Brazil" is already clear from
+               context.
+            -->
+          <_name>West ParÃ, RondÃnia</_name>
+        </timezone>
+        <timezone id="America/Recife">
+          <!-- Translators: This represents the time zone in the Brazilian
+               state of Pernambuco. See the comment on "BrasÃlia Time" for
+               more details. This string is only used in places where
+               "Brazil" is already clear from context.
+            -->
+          <_name>Pernambuco</_name>
+        </timezone>
+        <timezone id="America/Rio_Branco">
+          <!-- Translators: This represents the time zone in the Brazilian
+               state of Acre. See the comment on "BrasÃlia Time" for more
+               details. This string is only used in places where "Brazil"
+               is already clear from context.
+            -->
+          <_name>Acre</_name>
+        </timezone>
+        <timezone id="America/Sao_Paulo">
+          <!-- Translators: This represents the official "base" time zone
+               in Brazil, covering the capital city of BrasÃlia, and those
+               states that choose to follow it. Each Brazilian state
+               decides on its own each year whether or not to observe
+               Daylight Saving Time. The tzdata database breaks the states
+               up into groups of states that generally make the same
+               decision in a given year. Thus, in any given year, several
+               of the time zones will appear to be redundant, but exactly
+               which ones seem redundant may differ from year to year, and
+               there's no good way to identify the zones other than by
+               listing states.
+
+               Anyway, "BrasÃlia Time" is the most common timezone,
+               being used by about a third of the states in Brazil
+               (Distrito Federal, EspÃrito Santo, GoiÃs, Minas Gerais,
+               ParanÃ, Rio de Janeiro, Rio Grande do Sul, Santa
+               Catarina, and SÃo Paulo). This string is only used in
+               places where "Brazil" is already clear from context.
+            -->
+          <_name>BrasÃlia Time</_name>
+        </timezone>
+      </timezones>
       <tz-hint>America/Sao_Paulo</tz-hint>
       <state>
         <!-- Translators: this is a state/province/territory in Brazil -->
@@ -10289,6 +11232,9 @@
       <_name>British Virgin Islands</_name>
       <iso-code>VG</iso-code>
       <fips-code>VI</fips-code>
+      <timezones>
+        <timezone id="America/Tortola" />
+      </timezones>
       <tz-hint>America/Tortola</tz-hint>
       <city>
         <!-- Translators: this is the capital of British Virgin Islands -->
@@ -10316,6 +11262,9 @@
       <_name>Cayman Islands</_name>
       <iso-code>KY</iso-code>
       <fips-code>CJ</fips-code>
+      <timezones>
+        <timezone id="America/Cayman" />
+      </timezones>
       <tz-hint>America/Cayman</tz-hint>
       <city>
         <!-- Translators: this is the capital of Cayman Islands -->
@@ -10357,6 +11306,17 @@
         -->
       <iso-code>CL</iso-code>
       <fips-code>CI</fips-code>
+      <timezones>
+        <timezone id="America/Santiago">
+          <!-- Translators: This refers to the time zone for mainland
+               Chile (as opposed to the time zone for Easter Island).
+            -->
+          <_name>Mainland Chile</_name>
+        </timezone>
+        <timezone id="Pacific/Easter">
+          <_name>Easter Island</_name>
+        </timezone>
+      </timezones>
       <tz-hint>America/Santiago</tz-hint>
       <city>
         <!-- Translators: this is a city in Chile -->
@@ -10491,6 +11451,9 @@
         -->
       <iso-code>CO</iso-code>
       <fips-code>CO</fips-code>
+      <timezones>
+        <timezone id="America/Bogota" />
+      </timezones>
       <tz-hint>America/Bogota</tz-hint>
       <city>
         <!-- Translators: this is a city in Colombia -->
@@ -10642,6 +11605,9 @@
         -->
       <iso-code>CR</iso-code>
       <fips-code>CS</fips-code>
+      <timezones>
+        <timezone id="America/Costa_Rica" />
+      </timezones>
       <tz-hint>America/Costa_Rica</tz-hint>
       <city>
         <!-- Translators: this is a city in Costa Rica -->
@@ -10702,6 +11668,9 @@
         -->
       <iso-code>CU</iso-code>
       <fips-code>CU</fips-code>
+      <timezones>
+        <timezone id="America/Havana" />
+      </timezones>
       <tz-hint>America/Havana</tz-hint>
       <city>
         <!-- Translators: this is a city in Cuba -->
@@ -10816,6 +11785,9 @@
         -->
       <iso-code>DO</iso-code>
       <fips-code>DR</fips-code>
+      <timezones>
+        <timezone id="America/Santo_Domingo" />
+      </timezones>
       <tz-hint>America/Santo_Domingo</tz-hint>
       <city>
         <!-- Translators: this is a city in Dominican Republic -->
@@ -10897,6 +11869,19 @@
         -->
       <iso-code>EC</iso-code>
       <fips-code>EC</fips-code>
+      <timezones>
+        <timezone id="America/Guayaquil">
+          <!-- Translators: This refers to the time zone for mainland
+               Ecuador (as opposed to the time zone for the Galapagos
+               Islands).
+            -->
+          <_name>Mainland Ecuador</_name>
+        </timezone>
+        <timezone id="Pacific/Galapagos">
+          <!-- Translators: This is the time zone for the Galapagos Islands. -->
+          <_name>Galapagos Islands</_name>
+        </timezone>
+      </timezones>
       <tz-hint>America/Guayaquil</tz-hint>
       <city>
         <!-- Translators: this is a city in Ecuador -->
@@ -10944,6 +11929,9 @@
       <_name>El Salvador</_name>
       <iso-code>SV</iso-code>
       <fips-code>ES</fips-code>
+      <timezones>
+        <timezone id="America/El_Salvador" />
+      </timezones>
       <tz-hint>America/El_Salvador</tz-hint>
       <city>
         <!-- Translators: this is a city in El Salvador -->
@@ -10986,6 +11974,9 @@
       <_name>Falkland Islands (Malvinas)</_name>
       <iso-code>FK</iso-code>
       <fips-code>FK</fips-code>
+      <timezones>
+        <timezone id="Atlantic/Stanley" />
+      </timezones>
       <tz-hint>Atlantic/Stanley</tz-hint>
       <city>
         <!-- Translators: this is the capital of Falkland Islands
@@ -11007,6 +11998,9 @@
       <_name>French Guiana</_name>
       <iso-code>GF</iso-code>
       <fips-code>FG</fips-code>
+      <timezones>
+        <timezone id="America/Cayenne" />
+      </timezones>
       <tz-hint>America/Cayenne</tz-hint>
       <city>
         <!-- Translators: this is the capital of French Guiana -->
@@ -11024,6 +12018,9 @@
       <_name>Grenada</_name>
       <iso-code>GD</iso-code>
       <fips-code>GJ</fips-code>
+      <timezones>
+        <timezone id="America/Grenada" />
+      </timezones>
       <tz-hint>America/Grenada</tz-hint>
       <city>
         <!-- Translators: this is a city in Grenada -->
@@ -11053,6 +12050,9 @@
       <_name>Guadeloupe</_name>
       <iso-code>GP</iso-code>
       <fips-code>GP</fips-code>
+      <timezones>
+        <timezone id="America/Guadeloupe" />
+      </timezones>
       <tz-hint>America/Guadeloupe</tz-hint>
       <city>
         <!-- Translators: this is the capital of Guadeloupe -->
@@ -11080,6 +12080,9 @@
       <_name>Guatemala</_name>
       <iso-code>GT</iso-code>
       <fips-code>GT</fips-code>
+      <timezones>
+        <timezone id="America/Guatemala" />
+      </timezones>
       <tz-hint>America/Guatemala</tz-hint>
       <city>
         <!-- Translators: this is the capital of Guatemala -->
@@ -11147,6 +12150,9 @@
       <_name>Guyana</_name>
       <iso-code>GY</iso-code>
       <fips-code>GY</fips-code>
+      <timezones>
+        <timezone id="America/Guyana" />
+      </timezones>
       <tz-hint>America/Guyana</tz-hint>
       <city>
         <!-- Translators: this is the capital of Guyana -->
@@ -11168,6 +12174,9 @@
         -->
       <iso-code>HT</iso-code>
       <fips-code>HA</fips-code>
+      <timezones>
+        <timezone id="America/Port-au-Prince" />
+      </timezones>
       <tz-hint>America/Port-au-Prince</tz-hint>
     </country>
     <country>
@@ -11179,6 +12188,9 @@
         -->
       <iso-code>HN</iso-code>
       <fips-code>HO</fips-code>
+      <timezones>
+        <timezone id="America/Tegucigalpa" />
+      </timezones>
       <tz-hint>America/Tegucigalpa</tz-hint>
       <city>
         <!-- Translators: this is a city in Honduras -->
@@ -11326,6 +12338,9 @@
       <_name>Jamaica</_name>
       <iso-code>JM</iso-code>
       <fips-code>JM</fips-code>
+      <timezones>
+        <timezone id="America/Jamaica" />
+      </timezones>
       <tz-hint>America/Jamaica</tz-hint>
       <city>
         <!-- Translators: this is the capital of Jamaica -->
@@ -11355,6 +12370,9 @@
       <_name>Martinique</_name>
       <iso-code>MQ</iso-code>
       <fips-code>MB</fips-code>
+      <timezones>
+        <timezone id="America/Martinique" />
+      </timezones>
       <tz-hint>America/Martinique</tz-hint>
       <city>
         <!-- Translators: this is the capital of Martinique -->
@@ -11386,6 +12404,9 @@
         -->
       <iso-code>MS</iso-code>
       <fips-code>MH</fips-code>
+      <timezones>
+        <timezone id="America/Montserrat" />
+      </timezones>
       <tz-hint>America/Montserrat</tz-hint>
     </country>
     <country>
@@ -11396,6 +12417,9 @@
       <_name>Netherlands Antilles</_name>
       <iso-code>AN</iso-code>
       <fips-code>NT</fips-code>
+      <timezones>
+        <timezone id="America/Curacao" />
+      </timezones>
       <tz-hint>America/Curacao</tz-hint>
       <city>
         <!-- Translators: this is a city in Netherlands Antilles -->
@@ -11443,6 +12467,9 @@
       <_name>Nicaragua</_name>
       <iso-code>NI</iso-code>
       <fips-code>NU</fips-code>
+      <timezones>
+        <timezone id="America/Managua" />
+      </timezones>
       <tz-hint>America/Managua</tz-hint>
       <city>
         <!-- Translators: this is a city in Nicaragua -->
@@ -11527,6 +12554,9 @@
         -->
       <iso-code>PA</iso-code>
       <fips-code>PM</fips-code>
+      <timezones>
+        <timezone id="America/Panama" />
+      </timezones>
       <tz-hint>America/Panama</tz-hint>
       <city>
         <!-- Translators: this is a city in Panama -->
@@ -11574,6 +12604,9 @@
       <_name>Paraguay</_name>
       <iso-code>PY</iso-code>
       <fips-code>PA</fips-code>
+      <timezones>
+        <timezone id="America/Asuncion" />
+      </timezones>
       <tz-hint>America/Asuncion</tz-hint>
       <city>
         <!-- Translators: this is the capital of Paraguay -->
@@ -11610,6 +12643,9 @@
         -->
       <iso-code>PE</iso-code>
       <fips-code>PE</fips-code>
+      <timezones>
+        <timezone id="America/Lima" />
+      </timezones>
       <tz-hint>America/Lima</tz-hint>
       <city>
         <!-- Translators: this is a city in Peru -->
@@ -11837,6 +12873,9 @@
       <_name>Saint Lucia</_name>
       <iso-code>LC</iso-code>
       <fips-code>ST</fips-code>
+      <timezones>
+        <timezone id="America/St_Lucia" />
+      </timezones>
       <tz-hint>America/St_Lucia</tz-hint>
       <city>
         <!-- Translators: this is the capital of Saint Lucia -->
@@ -11877,6 +12916,9 @@
       <_name>Saint Martin</_name>
       <iso-code>MF</iso-code>
       <fips-code>RN</fips-code>
+      <timezones>
+        <timezone id="America/Marigot" />
+      </timezones>
       <tz-hint>America/Marigot</tz-hint>
     </country>
     <country>
@@ -11884,6 +12926,9 @@
       <_name>Saint Vincent and the Grenadines</_name>
       <iso-code>VC</iso-code>
       <fips-code>VC</fips-code>
+      <timezones>
+        <timezone id="America/St_Vincent" />
+      </timezones>
       <tz-hint>America/St_Vincent</tz-hint>
       <city>
         <!-- Translators: this is a city in Saint Vincent and the
@@ -11917,6 +12962,9 @@
       <_name>South Georgia and the South Sandwich Islands</_name>
       <iso-code>GS</iso-code>
       <fips-code>SX</fips-code>
+      <timezones>
+        <timezone id="Atlantic/South_Georgia" />
+      </timezones>
       <tz-hint>Atlantic/South_Georgia</tz-hint>
     </country>
     <country>
@@ -11928,6 +12976,9 @@
         -->
       <iso-code>SR</iso-code>
       <fips-code>NS</fips-code>
+      <timezones>
+        <timezone id="America/Paramaribo" />
+      </timezones>
       <tz-hint>America/Paramaribo</tz-hint>
       <city>
         <!-- Translators: this is the capital of Suriname -->
@@ -11955,6 +13006,9 @@
       <_name>Trinidad and Tobago</_name>
       <iso-code>TT</iso-code>
       <fips-code>TD</fips-code>
+      <timezones>
+        <timezone id="America/Port_of_Spain" />
+      </timezones>
       <tz-hint>America/Port_of_Spain</tz-hint>
       <city>
         <!-- Translators: this is a city in Trinidad and Tobago -->
@@ -11998,6 +13052,9 @@
         -->
       <iso-code>TC</iso-code>
       <fips-code>TK</fips-code>
+      <timezones>
+        <timezone id="America/Grand_Turk" />
+      </timezones>
       <tz-hint>America/Grand_Turk</tz-hint>
     </country>
     <country>
@@ -12005,6 +13062,9 @@
       <_name>Uruguay</_name>
       <iso-code>UY</iso-code>
       <fips-code>UY</fips-code>
+      <timezones>
+        <timezone id="America/Montevideo" />
+      </timezones>
       <tz-hint>America/Montevideo</tz-hint>
       <city>
         <!-- Translators: this is a city in Uruguay -->
@@ -12062,6 +13122,9 @@
       <_name>Venezuela</_name>
       <iso-code>VE</iso-code>
       <fips-code>VE</fips-code>
+      <timezones>
+        <timezone id="America/Caracas" />
+      </timezones>
       <tz-hint>America/Caracas</tz-hint>
       <city>
         <!-- Translators: this is a city in Venezuela -->
@@ -12417,6 +13480,9 @@
         -->
       <iso-code>AL</iso-code>
       <fips-code>AL</fips-code>
+      <timezones>
+        <timezone id="Europe/Tirane" />
+      </timezones>
       <tz-hint>Europe/Tirane</tz-hint>
       <city>
         <!-- Translators: this is a city in Albania -->
@@ -12472,6 +13538,9 @@
         -->
       <iso-code>AD</iso-code>
       <fips-code>AN</fips-code>
+      <timezones>
+        <timezone id="Europe/Andorra" />
+      </timezones>
       <tz-hint>Europe/Andorra</tz-hint>
     </country>
     <country>
@@ -12479,6 +13548,9 @@
       <_name>Austria</_name>
       <iso-code>AT</iso-code>
       <fips-code>AU</fips-code>
+      <timezones>
+        <timezone id="Europe/Vienna" />
+      </timezones>
       <tz-hint>Europe/Vienna</tz-hint>
       <city>
         <!-- Translators: this is a city in Austria.
@@ -12665,6 +13737,9 @@
         -->
       <iso-code>BY</iso-code>
       <fips-code>BO</fips-code>
+      <timezones>
+        <timezone id="Europe/Minsk" />
+      </timezones>
       <tz-hint>Europe/Minsk</tz-hint>
       <city>
         <!-- Translators: this is a city in Belarus -->
@@ -12747,6 +13822,9 @@
         -->
       <iso-code>BE</iso-code>
       <fips-code>BE</fips-code>
+      <timezones>
+        <timezone id="Europe/Brussels" />
+      </timezones>
       <tz-hint>Europe/Brussels</tz-hint>
       <state>
         <!-- Translators: This is a state in Belgium. local name (nl):
@@ -13086,6 +14164,9 @@
       <_name>Bosnia and Herzegovina</_name>
       <iso-code>BA</iso-code>
       <fips-code>BK</fips-code>
+      <timezones>
+        <timezone id="Europe/Sarajevo" />
+      </timezones>
       <tz-hint>Europe/Sarajevo</tz-hint>
       <city>
         <!-- Translators: this is a city in Bosnia and Herzegovina -->
@@ -13139,6 +14220,9 @@
         -->
       <iso-code>BG</iso-code>
       <fips-code>BU</fips-code>
+      <timezones>
+        <timezone id="Europe/Sofia" />
+      </timezones>
       <tz-hint>Europe/Sofia</tz-hint>
       <city>
         <!-- Translators: this is a city in Bulgaria -->
@@ -13254,6 +14338,9 @@
         -->
       <iso-code>HR</iso-code>
       <fips-code>HR</fips-code>
+      <timezones>
+        <timezone id="Europe/Zagreb" />
+      </timezones>
       <tz-hint>Europe/Zagreb</tz-hint>
       <city>
         <!-- Translators: this is a city in Croatia -->
@@ -13471,6 +14558,9 @@
       <_name>Cyprus</_name>
       <iso-code>CY</iso-code>
       <fips-code>CY</fips-code>
+      <timezones>
+        <timezone id="Asia/Nicosia" />
+      </timezones>
       <tz-hint>Asia/Nicosia</tz-hint>
       <city>
         <!-- Translators: this is a city in Cyprus -->
@@ -13537,6 +14627,9 @@
         -->
       <iso-code>CZ</iso-code>
       <fips-code>EZ</fips-code>
+      <timezones>
+        <timezone id="Europe/Prague" />
+      </timezones>
       <tz-hint>Europe/Prague</tz-hint>
       <city>
         <!-- Translators: this is a city in Czech Republic -->
@@ -13621,6 +14714,9 @@
         -->
       <iso-code>DK</iso-code>
       <fips-code>DA</fips-code>
+      <timezones>
+        <timezone id="Europe/Copenhagen" />
+      </timezones>
       <tz-hint>Europe/Copenhagen</tz-hint>
       <city>
         <!-- Translators: this is a city in Denmark -->
@@ -13875,6 +14971,9 @@
         -->
       <iso-code>EE</iso-code>
       <fips-code>EN</fips-code>
+      <timezones>
+        <timezone id="Europe/Tallinn" />
+      </timezones>
       <tz-hint>Europe/Tallinn</tz-hint>
       <city>
         <!-- Translators: this is a city in Estonia -->
@@ -13978,6 +15077,9 @@
         -->
       <iso-code>FO</iso-code>
       <fips-code>FO</fips-code>
+      <timezones>
+        <timezone id="Atlantic/Faroe" />
+      </timezones>
       <tz-hint>Atlantic/Faroe</tz-hint>
       <city>
         <!-- Translators: this is a city in Faroe Islands -->
@@ -14010,6 +15112,9 @@
       <iso-code>FI</iso-code>
       <fips-code>FI</fips-code>
       <pref-lang>fin</pref-lang>
+      <timezones>
+        <timezone id="Europe/Helsinki" />
+      </timezones>
       <tz-hint>Europe/Helsinki</tz-hint>
       <city>
         <!-- Translators: this is a city in Finland -->
@@ -14294,6 +15399,9 @@
         -->
       <iso-code>FR</iso-code>
       <fips-code>FR</fips-code>
+      <timezones>
+        <timezone id="Europe/Paris" />
+      </timezones>
       <tz-hint>Europe/Paris</tz-hint>
       <city>
         <!-- Translators: this is a city in France -->
@@ -15323,6 +16431,9 @@
         -->
       <iso-code>DE</iso-code>
       <fips-code>GM</fips-code>
+      <timezones>
+        <timezone id="Europe/Berlin" />
+      </timezones>
       <tz-hint>Europe/Berlin</tz-hint>
       <state>
         <!-- Translators: this is a state/province/territory in Germany -->
@@ -16479,6 +17590,9 @@
       <_name>Gibraltar</_name>
       <iso-code>GI</iso-code>
       <fips-code>GI</fips-code>
+      <timezones>
+        <timezone id="Europe/Gibraltar" />
+      </timezones>
       <tz-hint>Europe/Gibraltar</tz-hint>
       <city>
         <!-- Translators: this is the capital of Gibraltar -->
@@ -16506,6 +17620,9 @@
         -->
       <iso-code>GR</iso-code>
       <fips-code>GR</fips-code>
+      <timezones>
+        <timezone id="Europe/Athens" />
+      </timezones>
       <tz-hint>Europe/Athens</tz-hint>
       <city>
         <!-- Translators: this is a city in Greece -->
@@ -17081,6 +18198,11 @@
         -->
       <iso-code>GG</iso-code>
       <fips-code>GK</fips-code>
+      <timezones>
+        <timezone id="Europe/Guernsey">
+          <_name>GMT/BST</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Europe/Guernsey</tz-hint>
       <city>
         <!-- Translators: this is a city in Guernsey -->
@@ -17120,6 +18242,9 @@
         -->
       <iso-code>HU</iso-code>
       <fips-code>HU</fips-code>
+      <timezones>
+        <timezone id="Europe/Budapest" />
+      </timezones>
       <tz-hint>Europe/Budapest</tz-hint>
       <city>
         <!-- Translators: this is the capital of Hungary -->
@@ -17257,6 +18382,9 @@
       <_name>Iceland</_name>
       <iso-code>IS</iso-code>
       <fips-code>IC</fips-code>
+      <timezones>
+        <timezone id="Atlantic/Reykjavik" />
+      </timezones>
       <tz-hint>Atlantic/Reykjavik</tz-hint>
       <city>
         <!-- Translators: this is a city in Iceland -->
@@ -17310,6 +18438,14 @@
         -->
       <iso-code>IE</iso-code>
       <fips-code>EI</fips-code>
+      <timezones>
+        <timezone id="Europe/Dublin">
+          <!-- Translators: This is the time zone in Ireland (GMT in the
+               winter, and Irish Summer Time in the summer.)
+            -->
+          <_name>GMT/IST</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Europe/Dublin</tz-hint>
       <city>
         <!-- Translators: this is a city in Ireland.
@@ -17459,6 +18595,11 @@
       <_name>Isle of Man</_name>
       <iso-code>IM</iso-code>
       <fips-code>IM</fips-code>
+      <timezones>
+        <timezone id="Europe/Isle_of_Man">
+          <_name>GMT/BST</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Europe/Isle_of_Man</tz-hint>
       <city>
         <!-- Translators: this is the capital of Isle of Man -->
@@ -17492,6 +18633,9 @@
         -->
       <iso-code>IT</iso-code>
       <fips-code>IT</fips-code>
+      <timezones>
+        <timezone id="Europe/Rome" />
+      </timezones>
       <tz-hint>Europe/Rome</tz-hint>
       <city>
         <!-- Translators: this is a city in Italy -->
@@ -18375,6 +19519,11 @@
       <_name>Jersey</_name>
       <iso-code>JE</iso-code>
       <fips-code>JE</fips-code>
+      <timezones>
+        <timezone id="Europe/Jersey">
+          <_name>GMT/BST</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Europe/Jersey</tz-hint>
       <city>
         <!-- Translators: this is a city in Jersey -->
@@ -18412,6 +19561,9 @@
         -->
       <iso-code>LV</iso-code>
       <fips-code>LG</fips-code>
+      <timezones>
+        <timezone id="Europe/Riga" />
+      </timezones>
       <tz-hint>Europe/Riga</tz-hint>
       <city>
         <!-- Translators: this is a city in Latvia -->
@@ -18443,6 +19595,9 @@
         -->
       <iso-code>LI</iso-code>
       <fips-code>LS</fips-code>
+      <timezones>
+        <timezone id="Europe/Vaduz" />
+      </timezones>
       <tz-hint>Europe/Vaduz</tz-hint>
       <city>
         <!-- Translators: this is a city in Liechtenstein -->
@@ -18564,6 +19719,9 @@
         -->
       <iso-code>LT</iso-code>
       <fips-code>LH</fips-code>
+      <timezones>
+        <timezone id="Europe/Vilnius" />
+      </timezones>
       <tz-hint>Europe/Vilnius</tz-hint>
       <city>
         <!-- Translators: this is a city in Lithuania -->
@@ -18621,6 +19779,9 @@
       <_name>Luxembourg</_name>
       <iso-code>LU</iso-code>
       <fips-code>LU</fips-code>
+      <timezones>
+        <timezone id="Europe/Luxembourg" />
+      </timezones>
       <tz-hint>Europe/Luxembourg</tz-hint>
     </country>
     <country>
@@ -18643,6 +19804,9 @@
         -->
       <iso-code>MK</iso-code>
       <fips-code>MK</fips-code>
+      <timezones>
+        <timezone id="Europe/Skopje" />
+      </timezones>
       <tz-hint>Europe/Skopje</tz-hint>
       <city>
         <!-- Translators: this is a city in Macedonia -->
@@ -19190,6 +20354,9 @@
       <_name>Malta</_name>
       <iso-code>MT</iso-code>
       <fips-code>MT</fips-code>
+      <timezones>
+        <timezone id="Europe/Malta" />
+      </timezones>
       <tz-hint>Europe/Malta</tz-hint>
       <city>
         <!-- Translators: this is a city in Malta -->
@@ -19221,6 +20388,9 @@
         -->
       <iso-code>MD</iso-code>
       <fips-code>MD</fips-code>
+      <timezones>
+        <timezone id="Europe/Chisinau" />
+      </timezones>
       <tz-hint>Europe/Chisinau</tz-hint>
       <city>
         <!-- Translators: this is the capital of Moldova -->
@@ -19282,6 +20452,9 @@
         -->
       <iso-code>MC</iso-code>
       <fips-code>MN</fips-code>
+      <timezones>
+        <timezone id="Europe/Monaco" />
+      </timezones>
       <tz-hint>Europe/Monaco</tz-hint>
       <city>
         <!-- Translators: this is the capital of Monaco -->
@@ -19303,6 +20476,9 @@
         -->
       <iso-code>ME</iso-code>
       <fips-code>MJ</fips-code>
+      <timezones>
+        <timezone id="Europe/Podgorica" />
+      </timezones>
       <tz-hint>Europe/Podgorica</tz-hint>
       <city>
         <!-- Translators: this is a city in Montenegro -->
@@ -19338,6 +20514,9 @@
         -->
       <iso-code>NL</iso-code>
       <fips-code>NL</fips-code>
+      <timezones>
+        <timezone id="Europe/Amsterdam" />
+      </timezones>
       <tz-hint>Europe/Amsterdam</tz-hint>
       <city>
         <!-- Translators: this is a city in Netherlands -->
@@ -19576,6 +20755,9 @@
         -->
       <iso-code>NO</iso-code>
       <fips-code>NO</fips-code>
+      <timezones>
+        <timezone id="Europe/Oslo" />
+      </timezones>
       <tz-hint>Europe/Oslo</tz-hint>
       <city>
         <!-- Translators: this is a city in Norway -->
@@ -20192,6 +21374,9 @@
         -->
       <iso-code>PL</iso-code>
       <fips-code>PL</fips-code>
+      <timezones>
+        <timezone id="Europe/Warsaw" />
+      </timezones>
       <tz-hint>Europe/Warsaw</tz-hint>
       <city>
         <!-- Translators: this is a city in Poland -->
@@ -20301,6 +21486,28 @@
         -->
       <iso-code>PT</iso-code>
       <fips-code>PO</fips-code>
+      <timezones>
+        <timezone id="Atlantic/Azores">
+          <!-- Translators: This refers to the time zone for the Azores.
+               The string is only used in places where "Portugal" is
+               already understood from context.
+            -->
+          <_name>Azores</_name>
+        </timezone>
+        <timezone id="Atlantic/Madeira">
+          <!-- Translators: This refers to the time zone for the
+               Portuguese island of Madeira. The string is only used in
+               places where "Portugal" is already understood from context.
+            -->
+          <_name>Madeira</_name>
+        </timezone>
+        <timezone id="Europe/Lisbon">
+          <!-- Translators: This refers to the time zone for mainland
+               Portugal (as opposed to the time zone for the Azores).
+            -->
+          <_name>Mainland Portugal</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Europe/Lisbon</tz-hint>
       <city>
         <!-- Translators: this is a city in Portugal -->
@@ -20580,6 +21787,9 @@
         -->
       <iso-code>RO</iso-code>
       <fips-code>RO</fips-code>
+      <timezones>
+        <timezone id="Europe/Bucharest" />
+      </timezones>
       <tz-hint>Europe/Bucharest</tz-hint>
       <city>
         <!-- Translators: this is a city in Romania -->
@@ -20822,6 +22032,109 @@
         -->
       <iso-code>RU</iso-code>
       <fips-code>RS</fips-code>
+      <timezones>
+        <timezone id="Europe/Kaliningrad">
+          <!-- Translators: This is a Russian time zone, used in the city
+               and oblast of Kaliningrad on the Baltic sea. The Russian
+               name is "ÐÐÐÐÐÐÐÐÑÐÐÑÐÐÐ ÐÑÐÐÑ". This string is only used
+               in places where "Russia" is already clear from context.
+            -->
+          <_name>Kaliningrad Time</_name>
+        </timezone>
+        <timezone id="Europe/Moscow">
+          <!-- Translators: This is a Russian time zone, used in most of
+               the European part of Russia, including Moscow. The Russian
+               name is "ÐÐÑÐÐÐÑÐÐÐ ÐÑÐÐÑ". This string is only used in
+               places where "Russia" is already clear from context.
+            -->
+          <_name>Moscow Time</_name>
+          <obsoletes>Europe/Volgograd</obsoletes>
+        </timezone>
+        <timezone id="Europe/Samara">
+          <!-- Translators: This is a Russian time zone, used in the
+               Samara oblast and Udmurtia, on the eastern edge of European
+               Russia. The Russian name is "ÐÐÐÐÑÑÐÐÐ ÐÑÐÐÑ". This string
+               is only used in places where "Russia" is already clear from
+               context.
+            -->
+          <_name>Samara Time</_name>
+        </timezone>
+        <timezone id="Asia/Yekaterinburg">
+          <!-- Translators: This is a Russian time zone, used along the
+               Ural mountains, including the city of Yekaterinburg. The
+               Russian name is "ÐÐÐÑÐÑÐÐÐÑÑÐÑÐÐÐ ÐÑÐÐÑ". This string is
+               only used in places where "Russia" is already clear from
+               context.
+            -->
+          <_name>Yekaterinburg Time</_name>
+        </timezone>
+        <timezone id="Asia/Omsk">
+          <!-- Translators: This is a Russian time zone, used in the Omsk
+               and Novosibirsk oblasts and surrounding areas of
+               south-central Russia. The Russian name is "ÐÐÑÐÐÐ ÐÑÐÐÑ".
+               This string is only used in places where "Russia" is
+               already clear from context.
+            -->
+          <_name>Omsk Time</_name>
+          <obsoletes>Asia/Novosibirsk</obsoletes>
+        </timezone>
+        <timezone id="Asia/Krasnoyarsk">
+          <!-- Translators: This is a Russian time zone, used in the
+               Krasnoyarsk krai and surrounding areas of central Russia.
+               The Russian name is "ÐÑÐÑÐÐÑÑÑÐÐÐ ÐÑÐÐÑ". This string is
+               only used in places where "Russia" is already clear from
+               context.
+            -->
+          <_name>Krasnoyarsk Time</_name>
+        </timezone>
+        <timezone id="Asia/Irkutsk">
+          <!-- Translators: This is a Russian time zone, used in the
+               Irkutsk oblast and surrounding areas of south-central
+               Russia. The Russian name is "ÐÑÐÑÑÑÐÐÐ ÐÑÐÐÑ". This string
+               is only used in places where "Russia" is already clear from
+               context.
+            -->
+          <_name>Irkutsk Time</_name>
+        </timezone>
+        <timezone id="Asia/Yakutsk">
+          <!-- Translators: This is a Russian time zone, used in the city
+               of Yakutsk and surrounding areas of east-central Russia.
+               The Russian name is "ÐÐÑÑÑÐÐÐ ÐÑÐÐÑ". This string is only
+               used in places where "Russia" is already clear from
+               context.
+            -->
+          <_name>Yakutsk Time</_name>
+        </timezone>
+        <timezone id="Asia/Vladivostok">
+          <!-- Translators: This is a Russian time zone, used in the city
+               of Vladivostok and surrounding areas of eastern Russia. The
+               Russian name is "ÐÐÐÐÐÐÐÑÑÐÐÑÐÐÐ ÐÑÐÐÑ". This string is
+               only used in places where "Russia" is already clear from
+               context.
+            -->
+          <_name>Vladivostok Time</_name>
+          <obsoletes>Asia/Sakhalin</obsoletes>
+        </timezone>
+        <timezone id="Asia/Magadan">
+          <!-- Translators: This is a Russian time zone, used in the
+               Magadan oblast and surrounding areas of eastern Russia. The
+               Russian name is "ÐÐÐÐÐÐÐÑÐÐÐ ÐÑÐÐÑ". This string is only
+               used in places where "Russia" is already clear from
+               context.
+            -->
+          <_name>Magadan Time</_name>
+        </timezone>
+        <timezone id="Asia/Kamchatka">
+          <!-- Translators: This is a Russian time zone, used in the
+               Kamchatka krai and Chukotka okrug of far-eastern Russia.
+               The Russian name is "ÐÐÐÑÐÑÑÐÐÐ ÐÑÐÐÑ". This string is only
+               used in places where "Russia" is already clear from
+               context.
+            -->
+          <_name>Kamchatka Time</_name>
+          <obsoletes>Asia/Anadyr</obsoletes>
+        </timezone>
+      </timezones>
       <city>
         <!-- Translators: this is a city in Russia.
              The local name in Russian is "ÐÐÐÐÐÐ".
@@ -21556,6 +22869,9 @@
         -->
       <iso-code>SM</iso-code>
       <fips-code>SM</fips-code>
+      <timezones>
+        <timezone id="Europe/San_Marino" />
+      </timezones>
       <tz-hint>Europe/San_Marino</tz-hint>
       <city>
         <!-- Translators: this is a city in San Marino -->
@@ -21603,6 +22919,9 @@
       <_name>Serbia</_name>
       <iso-code>RS</iso-code>
       <fips-code>RB</fips-code>
+      <timezones>
+        <timezone id="Europe/Belgrade" />
+      </timezones>
       <tz-hint>Europe/Belgrade</tz-hint>
       <city>
         <!-- Translators: this is the capital of Serbia.
@@ -21663,6 +22982,9 @@
       <_name>Slovakia</_name>
       <iso-code>SK</iso-code>
       <fips-code>LO</fips-code>
+      <timezones>
+        <timezone id="Europe/Bratislava" />
+      </timezones>
       <tz-hint>Europe/Bratislava</tz-hint>
       <city>
         <!-- Translators: this is a city in Slovakia -->
@@ -21834,6 +23156,9 @@
         -->
       <iso-code>SI</iso-code>
       <fips-code>SI</fips-code>
+      <timezones>
+        <timezone id="Europe/Ljubljana" />
+      </timezones>
       <tz-hint>Europe/Ljubljana</tz-hint>
       <city>
         <!-- Translators: this is the capital of Slovenia -->
@@ -21879,6 +23204,26 @@
         -->
       <iso-code>ES</iso-code>
       <fips-code>SP</fips-code>
+      <timezones>
+        <timezone id="Atlantic/Canary">
+          <_name>Canary Islands</_name>
+        </timezone>
+        <timezone id="Europe/Madrid">
+          <!-- Translators: This refers to the time zone for mainland
+               Spain (as opposed to the time zone for the Canary
+               Islands).
+            -->
+          <_name>Mainland Spain</_name>
+        </timezone>
+        <timezone id="Africa/Ceuta">
+          <!-- Translators: This is the time zone for the Spanish cities
+               of Ceuta and Melilla, on the coast of Africa. The string is
+               only used in places where "Spain" is already clear from
+               context.
+            -->
+          <_name>Ceuta and Melilla</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Europe/Madrid</tz-hint>
       <city>
         <!-- Translators: this is a city in Spain -->
@@ -22494,6 +23839,9 @@
         -->
       <iso-code>SJ</iso-code>
       <fips-code>SV|JN</fips-code>
+      <timezones>
+        <timezone id="Arctic/Longyearbyen" />
+      </timezones>
       <tz-hint>Arctic/Longyearbyen</tz-hint>
       <city>
         <!-- Translators: this is the capital of Svalbard and Jan Mayen -->
@@ -22519,6 +23867,9 @@
         -->
       <iso-code>SE</iso-code>
       <fips-code>SW</fips-code>
+      <timezones>
+        <timezone id="Europe/Stockholm" />
+      </timezones>
       <tz-hint>Europe/Stockholm</tz-hint>
       <city>
         <!-- Translators: this is a city in Sweden -->
@@ -22894,6 +24245,9 @@
         -->
       <iso-code>CH</iso-code>
       <fips-code>SZ</fips-code>
+      <timezones>
+        <timezone id="Europe/Zurich" />
+      </timezones>
       <tz-hint>Europe/Zurich</tz-hint>
       <city>
         <!-- Translators: this is a city in Switzerland -->
@@ -23122,6 +24476,9 @@
         -->
       <iso-code>TR</iso-code>
       <fips-code>TU</fips-code>
+      <timezones>
+        <timezone id="Europe/Istanbul" />
+      </timezones>
       <tz-hint>Europe/Istanbul</tz-hint>
       <city>
         <!-- Translators: this is a city in Turkey -->
@@ -23463,6 +24820,13 @@
         -->
       <iso-code>UA</iso-code>
       <fips-code>UP</fips-code>
+      <timezones>
+        <timezone id="Europe/Kiev">
+          <obsoletes>Europe/Simferopol</obsoletes>
+          <obsoletes>Europe/Uzhgorod</obsoletes>
+          <obsoletes>Europe/Zaporozhye</obsoletes>
+        </timezone>
+      </timezones>
       <tz-hint>Europe/Kiev</tz-hint>
       <city>
         <!-- Translators: this is a city in Ukraine -->
@@ -23658,6 +25022,14 @@
         -->
       <iso-code>GB</iso-code>
       <fips-code>UK</fips-code>
+      <timezones>
+        <timezone id="Europe/London">
+          <!-- Translators: This is the time zone in the UK (GMT in the
+               winter, and British Summer Time in the summer.)
+            -->
+          <_name>GMT/BST</_name>
+        </timezone>
+      </timezones>
       <tz-hint>Europe/London</tz-hint>
       <city>
         <!-- Translators: this is a city in United Kingdom -->
@@ -27230,6 +28602,9 @@
       <_name>Vatican City</_name>
       <iso-code>VA</iso-code>
       <fips-code>VT</fips-code>
+      <timezones>
+        <timezone id="Europe/Vatican" />
+      </timezones>
       <tz-hint>Europe/Vatican</tz-hint>
     </country>
     <country>
@@ -27238,6 +28613,9 @@
       <iso-code>AX</iso-code>
       <fips-code>FI01</fips-code>
       <pref-lang>swe</pref-lang>
+      <timezones>
+        <timezone id="Europe/Mariehamn" />
+      </timezones>
       <tz-hint>Europe/Mariehamn</tz-hint>
       <city>
         <!-- Translators: this is a city in Ãland Islands.
@@ -27260,6 +28638,9 @@
       <_name>Bahrain</_name>
       <iso-code>BH</iso-code>
       <fips-code>BA</fips-code>
+      <timezones>
+        <timezone id="Asia/Bahrain" />
+      </timezones>
       <tz-hint>Asia/Bahrain</tz-hint>
       <city>
         <!-- Translators: this is a city in Bahrain.
@@ -27296,6 +28677,9 @@
         -->
       <iso-code>IR</iso-code>
       <fips-code>IR</fips-code>
+      <timezones>
+        <timezone id="Asia/Tehran" />
+      </timezones>
       <tz-hint>Asia/Tehran</tz-hint>
       <city>
         <!-- Translators: this is a city in Iran.
@@ -27848,6 +29232,9 @@
         -->
       <iso-code>IQ</iso-code>
       <fips-code>IZ</fips-code>
+      <timezones>
+        <timezone id="Asia/Baghdad" />
+      </timezones>
       <tz-hint>Asia/Baghdad</tz-hint>
     </country>
     <country>
@@ -27855,6 +29242,9 @@
       <_name>Israel</_name>
       <iso-code>IL</iso-code>
       <fips-code>IS</fips-code>
+      <timezones>
+        <timezone id="Asia/Jerusalem" />
+      </timezones>
       <tz-hint>Asia/Jerusalem</tz-hint>
       <city>
         <!-- Translators: this is a city in Israel -->
@@ -27922,6 +29312,9 @@
       <_name>Jordan</_name>
       <iso-code>JO</iso-code>
       <fips-code>JO</fips-code>
+      <timezones>
+        <timezone id="Asia/Amman" />
+      </timezones>
       <tz-hint>Asia/Amman</tz-hint>
       <city>
         <!-- Translators: this is a city in Jordan -->
@@ -27962,6 +29355,9 @@
       <_name>Kuwait</_name>
       <iso-code>KW</iso-code>
       <fips-code>KU</fips-code>
+      <timezones>
+        <timezone id="Asia/Kuwait" />
+      </timezones>
       <tz-hint>Asia/Kuwait</tz-hint>
       <city>
         <!-- Translators: this is the capital of Kuwait.
@@ -27982,6 +29378,9 @@
       <_name>Lebanon</_name>
       <iso-code>LB</iso-code>
       <fips-code>LE</fips-code>
+      <timezones>
+        <timezone id="Asia/Beirut" />
+      </timezones>
       <tz-hint>Asia/Beirut</tz-hint>
       <city>
         <!-- Translators: this is the capital of Lebanon.
@@ -28002,6 +29401,9 @@
       <_name>Oman</_name>
       <iso-code>OM</iso-code>
       <fips-code>MU</fips-code>
+      <timezones>
+        <timezone id="Asia/Muscat" />
+      </timezones>
       <tz-hint>Asia/Muscat</tz-hint>
       <city>
         <!-- Translators: this is a city in Oman -->
@@ -28042,6 +29444,9 @@
       <_name>Palestinian Territory</_name>
       <iso-code>PS</iso-code>
       <fips-code>GZ|WE</fips-code>
+      <timezones>
+        <timezone id="Asia/Gaza" />
+      </timezones>
       <tz-hint>Asia/Gaza</tz-hint>
     </country>
     <country>
@@ -28058,6 +29463,9 @@
         -->
       <iso-code>QA</iso-code>
       <fips-code>QA</fips-code>
+      <timezones>
+        <timezone id="Asia/Qatar" />
+      </timezones>
       <tz-hint>Asia/Qatar</tz-hint>
       <city>
         <!-- Translators: this is the capital of Qatar.
@@ -28087,6 +29495,9 @@
         -->
       <iso-code>SA</iso-code>
       <fips-code>SA</fips-code>
+      <timezones>
+        <timezone id="Asia/Riyadh" />
+      </timezones>
       <tz-hint>Asia/Riyadh</tz-hint>
       <city>
         <!-- Translators: this is a city in Saudi Arabia -->
@@ -28391,6 +29802,9 @@
       <_name>Syria</_name>
       <iso-code>SY</iso-code>
       <fips-code>SY</fips-code>
+      <timezones>
+        <timezone id="Asia/Damascus" />
+      </timezones>
       <tz-hint>Asia/Damascus</tz-hint>
       <city>
         <!-- Translators: this is a city in Syria -->
@@ -28461,6 +29875,9 @@
         -->
       <iso-code>AE</iso-code>
       <fips-code>AE</fips-code>
+      <timezones>
+        <timezone id="Asia/Dubai" />
+      </timezones>
       <tz-hint>Asia/Dubai</tz-hint>
       <city>
         <!-- Translators: this is the capital of United Arab Emirates.
@@ -28546,6 +29963,9 @@
         -->
       <iso-code>YE</iso-code>
       <fips-code>YM</fips-code>
+      <timezones>
+        <timezone id="Asia/Aden" />
+      </timezones>
       <tz-hint>Asia/Aden</tz-hint>
       <city>
         <!-- Translators: this is a city in Yemen -->
@@ -28705,6 +30125,114 @@
         -->
       <iso-code>CA</iso-code>
       <fips-code>CA</fips-code>
+      <timezones>
+        <timezone id="America/Vancouver">
+          <!-- Translators: This is the time zone used on most of the west
+               coast of North America. In Mexico it is called "Tiempo del
+               PacÃfico" and in French-speaking parts of Canada it is
+               called "Heure du Pacifique". The string is only used in
+               places where "US", "Canada" or "Mexico" is already clear
+               from the context.
+            -->
+          <_name>Pacific Time</_name>
+          <obsoletes>America/Dawson</obsoletes>
+          <obsoletes>America/Whitehorse</obsoletes>
+        </timezone>
+        <timezone id="America/Edmonton">
+          <!-- Translators: This is the time zone used in the central-west
+               part of North America (ie, the Rocky Mountains). In Mexico
+               it is called "Tiempo de la MontaÃa", and in French-speaking
+               parts of Canada it is called "Heure des Rocheuses". The
+               string is only used in places where "US", "Canada" or
+               "Mexico" is already clear from the context.
+            -->
+          <_name>Mountain Time</_name>
+          <obsoletes>America/Cambridge_Bay</obsoletes>
+          <obsoletes>America/Inuvik</obsoletes>
+          <obsoletes>America/Yellowknife</obsoletes>
+        </timezone>
+        <timezone id="America/Dawson_Creek">
+          <!-- Translators: This represents the time zone in the
+               northeastern part of the Canadian province of British
+               Columbia (BC), which is part of the "Mountain Time" zone,
+               but does not observe Daylight Saving Time with the rest of
+               the zone.
+            -->
+          <_name>Mountain Time, no DST (Northeast BC)</_name>
+        </timezone>
+        <timezone id="America/Winnipeg">
+          <!-- Translators: This is the time zone used in the central-east
+               part of North America. In Mexico it is called "Tiempo del
+               Centro", and in French-speaking parts of Canada it is
+               called "Heure du Centre". The string is only used in places
+               where "US", "Canada" or "Mexico" is already clear from the
+               context.
+            -->
+          <_name>Central Time</_name>
+          <obsoletes>America/Rainy_River</obsoletes>
+          <obsoletes>America/Rankin_Inlet</obsoletes>
+        </timezone>
+        <timezone id="America/Regina">
+          <!-- Translators: This represents the time zone in the Canadian
+               province of Saskatchewan, which is part of the "Central
+               Time" zone, but does not observe Daylight Saving Time with
+               the rest of the zone.
+            -->
+          <_name>Central Time, no DST (Saskatchewan)</_name>
+          <obsoletes>America/Swift_Current</obsoletes>
+        </timezone>
+        <timezone id="America/Toronto">
+          <!-- Translators: This is the time zone used on the east coast
+               of the United States, and the corresponding (non-coastal)
+               part of Canada. In French-speaking parts of Canada it is
+               called "Heure de l'Est". The string is only used in places
+               where "US" or "Canada" is already clear from the context.
+            -->
+          <_name>Eastern Time</_name>
+          <obsoletes>America/Iqaluit</obsoletes>
+          <obsoletes>America/Montreal</obsoletes>
+          <obsoletes>America/Nipigon</obsoletes>
+          <obsoletes>America/Pangnirtung</obsoletes>
+          <obsoletes>America/Thunder_Bay</obsoletes>
+        </timezone>
+        <timezone id="America/Atikokan">
+          <!-- Translators: This represents the time zone in certain parts
+               of Canada (such as Southampton Island, Nunavut, and
+               Atikokan, Ontario) which are part of the "Eastern Time"
+               zone, but which do not observe Daylight Saving Time with
+               the rest of the zone.
+            -->
+          <_name>Eastern Time, no DST (Southampton Island, etc)</_name>
+          <obsoletes>America/Resolute</obsoletes>
+        </timezone>
+        <timezone id="America/Halifax">
+          <!-- Translators: This is the time zone used on the east coast
+               of Canada, in Bermuda, and on many Caribbean islands. In
+               French-speaking parts of Canada it is called "Heure de
+               l'Atlantique". The string is only used in places where a
+               country is already clear from the context.
+            -->
+          <_name>Atlantic Time</_name>
+          <obsoletes>America/Glace_Bay</obsoletes>
+          <obsoletes>America/Goose_Bay</obsoletes>
+          <obsoletes>America/Moncton</obsoletes>
+        </timezone>
+        <timezone id="America/Blanc-Sablon">
+          <!-- Translators: This represents the time zone in the far
+               eastern portion of the Canadian province of Quebec, which
+               is part of the "Atlantic Time" zone, but does not observe
+               Daylight Saving Time with the rest of the zone.
+            -->
+          <_name>Atlantic Time, no DST (Eastern Quebec)</_name>
+        </timezone>
+        <timezone id="America/St_Johns">
+          <!-- Translators: This is the time zone used in the Canadian
+               province of Newfoundland. In French-speaking parts of
+               Canada it is called "Heure de Terre-Neuve".
+            -->
+          <_name>Newfoundland Time</_name>
+        </timezone>
+      </timezones>
       <state>
         <!-- Translators: this is a state/province/territory in Canada -->
         <_name>Alberta</_name>
@@ -33196,6 +34724,25 @@
         -->
       <iso-code>MX</iso-code>
       <fips-code>MX</fips-code>
+      <timezones>
+        <!-- Translator comments for these timezone names appear in the
+             entry for Canada.
+          -->
+        <timezone id="America/Tijuana">
+          <_name>Pacific Time</_name>
+        </timezone>
+        <timezone id="America/Mazatlan">
+          <_name>Mountain Time</_name>
+          <obsoletes>America/Chihuahua</obsoletes>
+          <obsoletes>America/Hermosillo</obsoletes>
+        </timezone>
+        <timezone id="America/Mexico_City">
+          <_name>Central Time</_name>
+          <obsoletes>America/Cancun</obsoletes>
+          <obsoletes>America/Merida</obsoletes>
+          <obsoletes>America/Monterrey</obsoletes>
+        </timezone>
+      </timezones>
       <state>
         <!-- Translators: this is a state/province/territory in Mexico -->
         <_name>Aguascalientes</_name>
@@ -34016,6 +35563,9 @@
       <_name>Saint Pierre and Miquelon</_name>
       <iso-code>PM</iso-code>
       <fips-code>SB</fips-code>
+      <timezones>
+        <timezone id="America/Miquelon" />
+      </timezones>
       <tz-hint>America/Miquelon</tz-hint>
       <city>
         <!-- Translators: this is the capital of Saint Pierre and
@@ -34079,6 +35629,78 @@
         -->
       <iso-code>US</iso-code>
       <fips-code>US</fips-code>
+      <timezones>
+        <!-- Translator comments for PST, MST, CST, and EST appear in the
+             entry for Canada.
+          -->
+        <timezone id="America/Adak">
+          <!-- Translators: "Hawaiian-Aleutian Time" is the official name
+               of the time zone used in Hawaii and the Aleutian Islands of
+               Alaska in the United States. This string is for the time
+               zone as it is observed in the Aleutian Islands (with
+               Daylight Saving Time). It is only used in places where
+               "United States" is already clear from context.
+            -->
+          <_name>Hawaiian-Aleutian Time (Aleutian Islands)</_name>
+        </timezone>
+        <timezone id="Pacific/Honolulu">
+          <!-- Translators: "Hawaiian-Aleutian Time" is the official name
+               of the time zone used in Hawaii and the Aleutian Islands of
+               Alaska in the United States. This string is for the time
+               zone as it is observed in Hawaii, where they do not use
+               Daylight Saving Time. It is only used in places where
+               "United States" is already clear from context.
+            -->
+          <_name>Hawaiian-Aleutian Time, no DST (Hawaii)</_name>
+        </timezone>
+        <timezone id="America/Anchorage">
+          <!-- Translators: This is the time zone used in the majority of
+               Alaska in the United States. The string is only used in
+               places where "United States" is already clear from context.
+            -->
+          <_name>Alaska Time</_name>
+          <obsoletes>America/Juneau</obsoletes>
+          <obsoletes>America/Nome</obsoletes>
+          <obsoletes>America/Yakutat</obsoletes>
+        </timezone>
+        <timezone id="America/Los_Angeles">
+          <_name>Pacific Time</_name>
+        </timezone>
+        <timezone id="America/Denver">
+          <_name>Mountain Time</_name>
+          <obsoletes>America/Boise</obsoletes>
+          <obsoletes>America/Shiprock</obsoletes>
+        </timezone>
+        <timezone id="America/Phoenix">
+          <!-- Translators: This represents the time zone in the US state
+               of Arizona, which is part of the "Mountain Time" zone, but
+               does not observe Daylight Saving Time with the rest of the
+               zone. The string is only used in places where "United
+               States" is already clear from context.
+            -->
+          <_name>Mountain Time, no DST (Arizona)</_name>
+        </timezone>
+        <timezone id="America/Chicago">
+          <_name>Central Time</_name>
+          <obsoletes>America/Indiana/Knox</obsoletes>
+          <obsoletes>America/Indiana/Tell_City</obsoletes>
+          <obsoletes>America/Menominee</obsoletes> <!-- doot DOOO do do doo! -->
+          <obsoletes>America/North_Dakota/Center</obsoletes>
+          <obsoletes>America/North_Dakota/New_Salem</obsoletes>
+        </timezone>
+        <timezone id="America/New_York">
+          <_name>Eastern Time</_name>
+          <obsoletes>America/Detroit</obsoletes>
+          <obsoletes>America/Indiana/Indianapolis</obsoletes>
+          <obsoletes>America/Indiana/Marengo</obsoletes>
+          <obsoletes>America/Indiana/Petersburg</obsoletes>
+          <obsoletes>America/Indiana/Vevay</obsoletes>
+          <obsoletes>America/Indiana/Vincennes</obsoletes>
+          <obsoletes>America/Indiana/Winamac</obsoletes>
+          <obsoletes>America/Kentucky/Louisville</obsoletes>
+          <obsoletes>America/Kentucky/Monticello</obsoletes>
+        </timezone>
+      </timezones>
       <state>
         <!-- Translators: this is a state/province/territory in United
              States

Modified: trunk/data/locations.dtd
==============================================================================
--- trunk/data/locations.dtd	(original)
+++ trunk/data/locations.dtd	Mon Aug  4 12:04:12 2008
@@ -5,11 +5,17 @@
 <!ENTITY % name '(_name|name+)' >
 
 <!ELEMENT region (%name;, country+) >
-<!ELEMENT country (%name;, iso-code, fips-code+, pref-lang?, tz-hint?, (location|state|city)*) >
+<!ELEMENT country (%name;, iso-code, fips-code+, pref-lang?, timezones, tz-hint?, (location|state|city)*) >
 <!ELEMENT state (%name;, fips-code+, tz-hint?, (location|city)*) >
 <!ELEMENT city (%name;, coordinates?, zone?, radar?, location+) >
 <!ELEMENT location (%name;, code, tz-hint?, zone?, radar?, coordinates?) >
 
+<!ELEMENT timezones (timezone+) >
+<!ELEMENT timezone (_name?, name*, obsoletes*) >
+<!ATTLIST timezone
+  id CDATA #REQUIRED >
+<!ELEMENT obsoletes (#PCDATA) >
+
 <!ELEMENT _name (#PCDATA) >
 <!ELEMENT name (#PCDATA) >
 <!ATTLIST name

Modified: trunk/libgweather/Makefile.am
==============================================================================
--- trunk/libgweather/Makefile.am	(original)
+++ trunk/libgweather/Makefile.am	Mon Aug  4 12:04:12 2008
@@ -1,7 +1,10 @@
 lib_LTLIBRARIES = libgweather.la
 
 libgweatherincdir = $(includedir)/libgweather
-libgweatherinc_HEADERS = weather.h gweather-gconf.h gweather-prefs.h gweather-xml.h
+libgweatherinc_HEADERS = \
+	weather.h gweather-gconf.h gweather-prefs.h gweather-xml.h \
+	gweather-location.h location-entry.h \
+	gweather-timezone.h timezone-menu.h
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = gweather.pc
@@ -13,7 +16,12 @@
 	weather-sun.c \
 	gweather-prefs.c gweather-prefs.h \
 	gweather-gconf.c gweather-gconf.h \
-	gweather-xml.c gweather-xml.h
+	gweather-xml.c gweather-xml.h \
+	gweather-location.c gweather-location.h \
+	gweather-timezone.c gweather-timezone.h \
+	location-entry.c location-entry.h \
+	timezone-menu.c timezone-menu.h \
+	parser.c parser.h
 
 libgweather_la_CFLAGS = \
 	-I$(top_srcdir)			\
@@ -50,8 +58,20 @@
 	$(LIBSOUP_LIBS)	\
 	libgweather.la
 
+test_locations_SOURCES = test_locations.c
+
+test_locations_CFLAGS = \
+	-I$(top_srcdir)			\
+	-I$(srcdir)			\
+	$(WARN_CFLAGS)			\
+	$(GTK_CFLAGS)			\
+	$(GNOME_VFS_APPLETS_CFLAGS)	\
+	-DG_LOG_DOMAIN=\"GWeather\"
+
+test_locations_LDADD = libgweather.la
+
 noinst_HEADERS = weather-priv.h
-noinst_PROGRAMS = test_metar
+noinst_PROGRAMS = test_metar test_locations
 
 schemadir   = @GCONF_SCHEMA_FILE_DIR@
 schema_in_files = gweather.schemas.in

Added: trunk/libgweather/gweather-location.c
==============================================================================
--- (empty file)
+++ trunk/libgweather/gweather-location.c	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,567 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* gweather-locations.c - Location-handling code
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <string.h>
+#include <math.h>
+#include <locale.h>
+#include <gtk/gtk.h>
+#include <libxml/xmlreader.h>
+
+#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "gweather-location.h"
+#include "gweather-timezone.h"
+#include "parser.h"
+#include "weather-priv.h"
+
+struct _GWeatherLocation {
+    char *name, *sort_name;
+    GWeatherLocation *parent, **children;
+    GWeatherLocationLevel level;
+    char *country_code, *tz_hint;
+    char *station_code, *forecast_zone, *radar;
+    double latitude, longitude;
+    gboolean latlon_valid;
+    GWeatherTimezone **zones;
+
+    int ref_count;
+};
+
+static int
+sort_locations_by_name (gconstpointer a, gconstpointer b)
+{
+    GWeatherLocation *loc_a = *(GWeatherLocation **)a;
+    GWeatherLocation *loc_b = *(GWeatherLocation **)b;
+
+    return g_utf8_collate (loc_a->sort_name, loc_b->sort_name);
+}
+ 
+static int
+sort_locations_by_distance (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+    GWeatherLocation *loc_a = *(GWeatherLocation **)a;
+    GWeatherLocation *loc_b = *(GWeatherLocation **)b;
+    GWeatherLocation *city = (GWeatherLocation *)user_data;
+    double dist_a, dist_b;
+
+    dist_a = gweather_location_get_distance (loc_a, city);
+    dist_b = gweather_location_get_distance (loc_b, city);
+    if (dist_a < dist_b)
+	return -1;
+    else if (dist_a > dist_b)
+	return 1;
+    else
+	return 0;
+}
+
+/*
+ * Convert string of the form "DD-MM[-SS]H" to radians
+ * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
+ * Return value is positive for N,E; negative for S,W.
+ */
+static gboolean
+dmsh2rad (const char *latlon, double *value)
+{
+    char *p1, *p2;
+    int deg, min, sec, dir;
+
+    p1 = strchr (latlon, '-');
+    p2 = strrchr (latlon, '-');
+    if (p1 == NULL || p1 == latlon || p2 == p1 + 1)
+        return FALSE;
+
+    if (p1 == p2) {
+	sscanf (latlon, "%d-%d", &deg, &min);
+	sec = 0;
+    } else
+	sscanf (latlon, "%d-%d-%d", &deg, &min, &sec);
+    if (deg > 180 || min >= 60 || sec >= 60)
+	return FALSE;
+    *value = (double)((deg * 60 + min) * 60 + sec) * M_PI / 648000.0;
+
+    dir = g_ascii_toupper (latlon[strlen (latlon) - 1]);
+    if (dir == 'W' || dir == 'S')
+	*value = -*value;
+    else if (dir != 'E' && dir != 'N' && (*value != 0.0 || dir != '0'))
+	return FALSE;
+    return TRUE;
+}
+
+static gboolean
+parse_coordinates (const char *coordinates,
+		   double *latitude, double *longitude)
+{
+    char **pieces;
+    gboolean ret = FALSE;
+
+    pieces = g_strsplit (coordinates, " ", -1);
+    if (g_strv_length (pieces) == 2) {
+	ret = TRUE;
+	ret = ret && dmsh2rad (pieces[0], latitude);
+	ret = ret && dmsh2rad (pieces[1], longitude);
+    }
+
+    g_strfreev (pieces);
+    return ret;
+}
+
+static char *
+unparse_coordinates (double latitude, double longitude)
+{
+    int lat_d, lat_m, lat_s, lon_d, lon_m, lon_s;
+    char lat_dir, lon_dir;
+
+    latitude = latitude * 180.0 / M_PI;
+    longitude = longitude * 180.0 / M_PI;
+
+    if (latitude < 0.0) {
+	lat_dir = 'S';
+	latitude = -latitude;
+    } else
+	lat_dir = 'N';
+    if (longitude < 0.0) {
+	lon_dir = 'W';
+	longitude = -longitude;
+    } else
+	lon_dir = 'E';
+
+    lat_d = (int)latitude;
+    lat_m = (int)(latitude * 60.0) - lat_d * 60;
+    lat_s = (int)(latitude * 3600.0) - lat_d * 3600 - lat_m * 60;
+    lon_d = (int)longitude;
+    lon_m = (int)(longitude * 60.0) - lon_d * 60;
+    lon_s = (int)(longitude * 3600.0) - lon_d * 3600 - lon_m * 60;
+
+    return g_strdup_printf ("%02d-%02d-%02d%c %03d-%02d-%02d%c",
+			    lat_d, lat_m, lat_s, lat_dir,
+			    lon_d, lon_m, lon_s, lon_dir);
+}
+
+static GWeatherLocation *
+location_new_from_xml (GWeatherParser *parser, GWeatherLocationLevel level,
+		       GWeatherLocation *parent)
+{
+    GWeatherLocation *loc, *child;
+    GPtrArray *children = NULL;
+    const char *tagname;
+    char *value, *normalized;
+    int tagtype, i;
+
+    loc = g_slice_new0 (GWeatherLocation);
+    loc->parent = parent;
+    loc->level = level;
+    loc->ref_count = 1;
+    children = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	if (!strcmp (tagname, "name") && !loc->name) {
+	    value = gweather_parser_get_localized_value (parser);
+	    if (!value)
+		goto error_out;
+	    loc->name = g_strdup (value);
+	    xmlFree (value);
+	    normalized = g_utf8_normalize (loc->name, -1, G_NORMALIZE_ALL);
+	    loc->sort_name = g_utf8_casefold (normalized, -1);
+	    g_free (normalized);
+
+	} else if (!strcmp (tagname, "iso-code") && !loc->country_code) {
+	    value = gweather_parser_get_value (parser);
+	    if (!value)
+		goto error_out;
+	    loc->country_code = g_strdup (value);
+	    xmlFree (value);
+	} else if (!strcmp (tagname, "tz-hint") && !loc->tz_hint) {
+	    value = gweather_parser_get_value (parser);
+	    if (!value)
+		goto error_out;
+	    loc->tz_hint = g_strdup (value);
+	    xmlFree (value);
+	} else if (!strcmp (tagname, "code") && !loc->station_code) {
+	    value = gweather_parser_get_value (parser);
+	    if (!value)
+		goto error_out;
+	    loc->station_code = g_strdup (value);
+	    xmlFree (value);
+	} else if (!strcmp (tagname, "coordinates") && !loc->latlon_valid) {
+	    value = gweather_parser_get_value (parser);
+	    if (!value)
+		goto error_out;
+	    if (parse_coordinates (value, &loc->latitude, &loc->longitude))
+		loc->latlon_valid = TRUE;
+	    xmlFree (value);
+	} else if (!strcmp (tagname, "zone") && !loc->forecast_zone) {
+	    value = gweather_parser_get_value (parser);
+	    if (!value)
+		goto error_out;
+	    loc->forecast_zone = g_strdup (value);
+	    xmlFree (value);
+	} else if (!strcmp (tagname, "radar") && !loc->radar) {
+	    value = gweather_parser_get_value (parser);
+	    if (!value)
+		goto error_out;
+	    loc->radar = g_strdup (value);
+	    xmlFree (value);
+
+	} else if (!strcmp (tagname, "region")) {
+	    child = location_new_from_xml (parser, GWEATHER_LOCATION_REGION, loc);
+	    if (!child)
+		goto error_out;
+	    if (parser->use_regions)
+		g_ptr_array_add (children, child);
+	    else {
+		if (child->children) {
+		    for (i = 0; child->children[i]; i++)
+			g_ptr_array_add (children, gweather_location_ref (child->children[i]));
+		}
+		gweather_location_unref (child);
+	    }
+	} else if (!strcmp (tagname, "country")) {
+	    child = location_new_from_xml (parser, GWEATHER_LOCATION_COUNTRY, loc);
+	    if (!child)
+		goto error_out;
+	    g_ptr_array_add (children, child);
+	} else if (!strcmp (tagname, "state")) {
+	    child = location_new_from_xml (parser, GWEATHER_LOCATION_ADM1, loc);
+	    if (!child)
+		goto error_out;
+	    g_ptr_array_add (children, child);
+	} else if (!strcmp (tagname, "city")) {
+	    child = location_new_from_xml (parser, GWEATHER_LOCATION_CITY, loc);
+	    if (!child)
+		goto error_out;
+	    g_ptr_array_add (children, child);
+	} else if (!strcmp (tagname, "location")) {
+	    child = location_new_from_xml (parser, GWEATHER_LOCATION_WEATHER_STATION, loc);
+	    if (!child)
+		goto error_out;
+	    g_ptr_array_add (children, child);
+
+	} else if (!strcmp (tagname, "timezones")) {
+	    loc->zones = gweather_timezones_parse_xml (parser);
+	    if (!loc->zones)
+		goto error_out;
+
+	} else {
+	    if (xmlTextReaderNext (parser->xml) != 1)
+		goto error_out;
+	}
+    }
+    if (xmlTextReaderRead (parser->xml) != 1 && parent)
+	goto error_out;
+
+    if (children->len) {
+	if (level == GWEATHER_LOCATION_CITY)
+	    g_ptr_array_sort_with_data (children, sort_locations_by_distance, loc);
+	else
+	    g_ptr_array_sort (children, sort_locations_by_name);
+
+	g_ptr_array_add (children, NULL);
+	loc->children = (GWeatherLocation **)g_ptr_array_free (children, FALSE);
+    } else
+	g_ptr_array_free (children, TRUE);
+
+    return loc;
+
+error_out:
+    gweather_location_unref (loc);
+    for (i = 0; i < children->len; i++)
+	gweather_location_unref (children->pdata[i]);
+    g_ptr_array_free (children, TRUE);
+
+    return NULL;
+}
+
+GWeatherLocation *
+gweather_location_new_world (gboolean use_regions)
+{
+    GWeatherParser *parser;
+    GWeatherLocation *world;
+
+    parser = gweather_parser_new (use_regions);
+    if (!parser)
+	return NULL;
+
+    world = location_new_from_xml (parser, GWEATHER_LOCATION_WORLD, NULL);
+
+    gweather_parser_free (parser);
+    return world;
+}
+
+GWeatherLocation *
+gweather_location_ref (GWeatherLocation *loc)
+{
+    loc->ref_count++;
+    return loc;
+}
+
+void
+gweather_location_unref (GWeatherLocation *loc)
+{
+    int i;
+
+    if (--loc->ref_count)
+	return;
+    
+    g_free (loc->name);
+    g_free (loc->sort_name);
+    g_free (loc->country_code);
+    g_free (loc->tz_hint);
+    g_free (loc->station_code);
+    g_free (loc->forecast_zone);
+    g_free (loc->radar);
+
+    if (loc->children) {
+	for (i = 0; loc->children[i]; i++) {
+	    loc->children[i]->parent = NULL;
+	    gweather_location_unref (loc->children[i]);
+	}
+	g_free (loc->children);
+    }
+
+    if (loc->zones) {
+	for (i = 0; loc->zones[i]; i++)
+	    gweather_timezone_unref (loc->zones[i]);
+	g_free (loc->zones);
+    }
+
+    g_slice_free (GWeatherLocation, loc);
+}
+
+const char *
+gweather_location_get_name (GWeatherLocation *loc)
+{
+    return loc->name;
+}
+
+const char *
+gweather_location_get_sort_name (GWeatherLocation *loc)
+{
+    return loc->sort_name;
+}
+
+GWeatherLocationLevel
+gweather_location_get_level (GWeatherLocation *loc)
+{
+    return loc->level;
+}
+
+GWeatherLocation *
+gweather_location_get_parent (GWeatherLocation *loc)
+{
+    return loc->parent;
+}
+
+GWeatherLocation **
+gweather_location_get_children (GWeatherLocation *loc)
+{
+    gweather_location_ref (loc);
+    if (loc->children)
+	return loc->children;
+    else
+	return g_new0 (GWeatherLocation *, 1);
+}
+
+void
+gweather_location_free_children (GWeatherLocation  *loc,
+				 GWeatherLocation **children)
+{
+    if (!loc->children)
+	g_free (children);
+    gweather_location_unref (loc);
+}
+
+gboolean
+gweather_location_has_coords (GWeatherLocation *loc)
+{
+    return loc->latlon_valid;
+}
+
+void
+gweather_location_get_coords (GWeatherLocation *loc,
+			      double *latitude, double *longitude)
+{
+    //g_return_if_fail (loc->latlon_valid);
+
+    *latitude = loc->latitude / M_PI * 180.0;
+    *longitude = loc->longitude / M_PI * 180.0;
+}
+
+double
+gweather_location_get_distance (GWeatherLocation *loc, GWeatherLocation *loc2)
+{
+    /* average radius of the earth in km */
+    static const double radius = 6372.795;
+
+    //g_return_val_if_fail (loc->latlon_valid, 0.0);
+    //g_return_val_if_fail (loc2->latlon_valid, 0.0);
+
+    return acos (cos (loc->latitude) * cos (loc2->latitude) * cos (loc->longitude - loc2->longitude) +
+		 sin (loc->latitude) * sin (loc2->latitude)) * radius;
+}
+
+const char *
+gweather_location_get_country (GWeatherLocation *loc)
+{
+    while (loc->parent && !loc->country_code)
+	loc = loc->parent;
+    return loc->country_code;
+}
+
+GWeatherTimezone *
+gweather_location_get_timezone (GWeatherLocation *loc)
+{
+    const char *tz_hint;
+    int i;
+
+    while (loc && !loc->tz_hint)
+	loc = loc->parent;
+    if (!loc)
+	return NULL;
+    tz_hint = loc->tz_hint;
+
+    while (loc) {
+	while (loc && !loc->zones)
+	    loc = loc->parent;
+	if (!loc)
+	    return NULL;
+	for (i = 0; loc->zones[i]; i++) {
+	    if (!strcmp (tz_hint, gweather_timezone_get_tzid (loc->zones[i])))
+		return loc->zones[i];
+	}
+	loc = loc->parent;
+    }
+
+    return NULL;
+}
+
+static void
+add_timezones (GWeatherLocation *loc, GPtrArray *zones)
+{
+    int i;
+
+    if (loc->zones) {
+	for (i = 0; loc->zones[i]; i++)
+	    g_ptr_array_add (zones, gweather_timezone_ref (loc->zones[i]));
+    }
+    if (loc->level < GWEATHER_LOCATION_COUNTRY && loc->children) {
+	for (i = 0; loc->children[i]; i++)
+	    add_timezones (loc->children[i], zones);
+    }
+}
+
+GWeatherTimezone **
+gweather_location_get_timezones (GWeatherLocation *loc)
+{
+    GPtrArray *zones;
+
+    zones = g_ptr_array_new ();
+    add_timezones (loc, zones);
+    g_ptr_array_add (zones, NULL);
+    return (GWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+}
+
+void
+gweather_location_free_timezones (GWeatherLocation  *loc,
+				  GWeatherTimezone **zones)
+{
+    int i;
+
+    for (i = 0; zones[i]; i++)
+	gweather_timezone_unref (zones[i]);
+    g_free (zones);
+}
+
+const char *
+gweather_location_get_code (GWeatherLocation *loc)
+{
+    return loc->station_code;
+}
+
+char *
+gweather_location_get_city_name (GWeatherLocation *loc)
+{
+    if (loc->level != GWEATHER_LOCATION_WEATHER_STATION ||
+	!loc->parent ||
+	loc->parent->level != GWEATHER_LOCATION_CITY)
+	return NULL;
+
+    return g_strdup (loc->parent->name);
+}
+
+WeatherLocation *
+gweather_location_to_weather_location (GWeatherLocation *gloc,
+				       const char *name)
+{
+    const char *code = NULL, *zone = NULL, *radar = NULL, *tz_hint = NULL;
+    GWeatherLocation *l;
+    WeatherLocation *wloc;
+    char *coords;
+
+    if (!name)
+	name = gweather_location_get_name (gloc);
+
+    if (gloc->level == GWEATHER_LOCATION_CITY && gloc->children)
+	l = gloc->children[0];
+    else
+	l = gloc;
+
+    if (l->latlon_valid)
+	coords = unparse_coordinates (l->latitude, l->longitude);
+    else
+	coords = NULL;
+
+    while (l && (!code || !zone || !radar || !tz_hint)) {
+	if (!code && l->station_code)
+	    code = l->station_code;
+	if (!zone && l->forecast_zone)
+	    zone = l->forecast_zone;
+	if (!radar && l->radar)
+	    radar = l->radar;
+	if (!tz_hint && l->tz_hint)
+	    tz_hint = l->tz_hint;
+	l = l->parent;
+    }
+
+    wloc = weather_location_new (name, code, zone, radar, coords,
+				 gweather_location_get_country (gloc),
+				 tz_hint);
+    g_free (coords);
+    return wloc;
+}
+
+WeatherInfo *
+gweather_location_get_weather (GWeatherLocation *loc)
+{
+    WeatherLocation *wloc;
+    WeatherInfo *info;
+
+    wloc = gweather_location_to_weather_location (loc, NULL);
+    info = weather_info_new (wloc, NULL, NULL, NULL);
+    weather_location_free (wloc);
+    return info;
+}

Added: trunk/libgweather/gweather-location.h
==============================================================================
--- (empty file)
+++ trunk/libgweather/gweather-location.h	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,83 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* gweather-locations.c - Location-handling code
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef __GWEATHER_LOCATIONS_H__
+#define __GWEATHER_LOCATIONS_H__
+
+#ifndef GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#error "libgweather should only be used if you understand that it's subject to change, and is not supported as a fixed API/ABI or as part of the platform"
+#endif
+
+#include <glib.h>
+#include <libgweather/gweather-timezone.h>
+#include <libgweather/weather.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GWeatherLocation GWeatherLocation;
+typedef struct _GWeatherWeather  GWeatherWeather;
+typedef struct _GWeatherForecast GWeatherForecast;
+
+typedef enum {
+    GWEATHER_LOCATION_WORLD,
+    GWEATHER_LOCATION_REGION,
+    GWEATHER_LOCATION_COUNTRY,
+    /* ADM1 = first-order administrative division = state/province, etc */
+    GWEATHER_LOCATION_ADM1,
+    /* ADM2 = second-order division = county, etc */
+    GWEATHER_LOCATION_ADM2,
+    GWEATHER_LOCATION_CITY,
+    GWEATHER_LOCATION_WEATHER_STATION
+} GWeatherLocationLevel;
+
+GWeatherLocation      *gweather_location_new_world      (gboolean           use_regions);
+GWeatherLocation      *gweather_location_ref            (GWeatherLocation  *loc);
+void                   gweather_location_unref          (GWeatherLocation  *loc);
+
+const char            *gweather_location_get_name       (GWeatherLocation  *loc);
+const char            *gweather_location_get_sort_name  (GWeatherLocation  *loc);
+GWeatherLocationLevel  gweather_location_get_level      (GWeatherLocation  *loc);
+GWeatherLocation      *gweather_location_get_parent     (GWeatherLocation  *loc);
+
+GWeatherLocation     **gweather_location_get_children   (GWeatherLocation  *loc);
+void                   gweather_location_free_children  (GWeatherLocation  *loc,
+							 GWeatherLocation **children);
+
+gboolean               gweather_location_has_coords     (GWeatherLocation  *loc);
+void                   gweather_location_get_coords     (GWeatherLocation  *loc,
+							 double            *latitude,
+							 double            *longitude);
+double                 gweather_location_get_distance   (GWeatherLocation  *loc,
+							 GWeatherLocation  *loc2);
+
+const char            *gweather_location_get_country    (GWeatherLocation  *loc);
+
+GWeatherTimezone      *gweather_location_get_timezone   (GWeatherLocation  *loc);
+GWeatherTimezone     **gweather_location_get_timezones  (GWeatherLocation  *loc);
+void                   gweather_location_free_timezones (GWeatherLocation  *loc,
+							 GWeatherTimezone **zones);
+
+const char            *gweather_location_get_code       (GWeatherLocation  *loc);
+char                  *gweather_location_get_city_name  (GWeatherLocation  *loc);
+
+WeatherInfo           *gweather_location_get_weather    (GWeatherLocation  *loc);
+
+G_END_DECLS
+
+#endif /* __GWEATHER_LOCATIONS_H__ */

Added: trunk/libgweather/gweather-timezone.c
==============================================================================
--- (empty file)
+++ trunk/libgweather/gweather-timezone.c	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,283 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* gweather-timezone.c - Timezone handling
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <string.h>
+
+#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "gweather-timezone.h"
+#include "parser.h"
+
+struct _GWeatherTimezone {
+    char *id, *name;
+    int offset, dst_offset;
+    gboolean has_dst;
+
+    int ref_count;
+};
+
+#define ZONEINFO_DIR "/usr/share/zoneinfo"
+
+#define TZ_MAGIC "TZif"
+#define TZ_HEADER_SIZE 44
+#define TZ_TIMECNT_OFFSET 32
+#define TZ_TRANSITIONS_OFFSET 44
+
+#define TZ_TTINFO_SIZE 6
+#define TZ_TTINFO_GMTOFF_OFFSET 0
+#define TZ_TTINFO_ISDST_OFFSET 4
+
+static gboolean
+parse_tzdata (const char *tzname, time_t start, time_t end,
+	      int *offset, gboolean *has_dst, int *dst_offset)
+{
+    char *filename, *contents;
+    gsize length;
+    int timecnt, transitions_size, ttinfo_map_size;
+    int initial_transition = -1, second_transition = -1;
+    gint32 *transitions;
+    char *ttinfo_map, *ttinfos;
+    gint32 initial_offset, second_offset;
+    char initial_isdst, second_isdst;
+    int i;
+
+    filename = g_build_filename (ZONEINFO_DIR, tzname, NULL);
+    if (!g_file_get_contents (filename, &contents, &length, NULL)) {
+	g_free (filename);
+	return FALSE;
+    }
+    g_free (filename);
+
+    if (length < TZ_HEADER_SIZE ||
+	strncmp (contents, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) {
+	g_free (contents);
+	return FALSE;
+    }
+
+    timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+    transitions = (void *)(contents + TZ_TRANSITIONS_OFFSET);
+    transitions_size = timecnt * sizeof (*transitions);
+    ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
+    ttinfo_map_size = timecnt;
+    ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+
+    /* @transitions is an array of @timecnt time_t values. We need to
+     * find the transition into the current offset, which is the last
+     * transition before @start. If the following transition is before
+     * @end, then note that one too, since it presumably means we're
+     * doing DST.
+     */
+    for (i = 1; i < timecnt && initial_transition == -1; i++) {
+	if (GINT32_FROM_BE (transitions[i]) > start) {
+	    initial_transition = ttinfo_map[i - 1];
+	    if (GINT32_FROM_BE (transitions[i]) < end)
+		second_transition = ttinfo_map[i];
+	}
+    }
+    if (initial_transition == -1) {
+	if (timecnt)
+	    initial_transition = ttinfo_map[timecnt - 1];
+	else
+	    initial_transition = 0;
+    }
+
+    /* Copy the data out of the corresponding ttinfo structs */
+    initial_offset = *(gint32 *)(ttinfos +
+				 initial_transition * TZ_TTINFO_SIZE +
+				 TZ_TTINFO_GMTOFF_OFFSET);
+    initial_offset = GINT32_FROM_BE (initial_offset);
+    initial_isdst = *(ttinfos +
+		      initial_transition * TZ_TTINFO_SIZE +
+		      TZ_TTINFO_ISDST_OFFSET);
+
+    if (second_transition != -1) {
+	second_offset = *(gint32 *)(ttinfos +
+				    second_transition * TZ_TTINFO_SIZE +
+				    TZ_TTINFO_GMTOFF_OFFSET);
+	second_offset = GINT32_FROM_BE (second_offset);
+	second_isdst = *(ttinfos +
+			 second_transition * TZ_TTINFO_SIZE +
+			 TZ_TTINFO_ISDST_OFFSET);
+
+	*has_dst = (initial_isdst != second_isdst);
+    } else
+	*has_dst = FALSE;
+
+    if (!*has_dst)
+	*offset = initial_offset / 60;
+    else {
+	if (initial_isdst) {
+	    *offset = second_offset / 60;
+	    *dst_offset = initial_offset / 60;
+	} else {
+	    *offset = initial_offset / 60;
+	    *dst_offset = second_offset / 60;
+	}
+    }
+
+    g_free (contents);
+    return TRUE;
+}
+
+static GWeatherTimezone *
+parse_timezone (GWeatherParser *parser)
+{
+    GWeatherTimezone *zone = NULL;
+    char *id = NULL, *name = NULL;
+    int offset, dst_offset;
+    gboolean has_dst = FALSE;
+
+    id = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "id");
+    if (!id) {
+	xmlTextReaderNext (parser->xml);
+	return NULL;
+    }
+
+    if (!xmlTextReaderIsEmptyElement (parser->xml)) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (id);
+	    return NULL;
+	}
+
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT) {
+		if (xmlTextReaderRead (parser->xml) != 1)
+		    break;
+		continue;
+	    }
+
+	    if (!strcmp ((const char *) xmlTextReaderConstName (parser->xml), "name"))
+		name = gweather_parser_get_localized_value (parser);
+	    else {
+		if (xmlTextReaderNext (parser->xml) != 1)
+		    break;
+	    }
+	}
+    }
+
+    if (parse_tzdata (id, parser->year_start, parser->year_end,
+		      &offset, &has_dst, &dst_offset)) {
+	zone = g_slice_new0 (GWeatherTimezone);
+	zone->ref_count = 1;
+	zone->id = g_strdup (id);
+	zone->name = g_strdup (name);
+	zone->offset = offset;
+	zone->has_dst = has_dst;
+	zone->dst_offset = dst_offset;
+    }
+
+    xmlFree (id);
+    if (name)
+	xmlFree (name);
+
+    return zone;
+}
+
+GWeatherTimezone **
+gweather_timezones_parse_xml (GWeatherParser *parser)
+{
+    GPtrArray *zones;
+    GWeatherTimezone *zone;
+    const char *tagname;
+    int tagtype, i;
+
+    zones = g_ptr_array_new ();
+
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+    while ((tagtype = xmlTextReaderNodeType (parser->xml)) !=
+	   XML_READER_TYPE_END_ELEMENT) {
+	if (tagtype != XML_READER_TYPE_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1)
+		goto error_out;
+	    continue;
+	}
+
+	tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+	if (!strcmp (tagname, "timezone")) {
+	    zone = parse_timezone (parser);
+	    if (!zone)
+		goto error_out;
+	    g_ptr_array_add (zones, zone);
+	}
+
+	if (xmlTextReaderNext (parser->xml) != 1)
+	    goto error_out;
+    }
+    if (xmlTextReaderRead (parser->xml) != 1)
+	goto error_out;
+
+    g_ptr_array_add (zones, NULL);
+    return (GWeatherTimezone **)g_ptr_array_free (zones, FALSE);
+
+error_out:
+    for (i = 0; i < zones->len; i++)
+	gweather_timezone_unref (zones->pdata[i]);
+    g_ptr_array_free (zones, TRUE);
+    return NULL;
+}
+
+GWeatherTimezone *
+gweather_timezone_ref (GWeatherTimezone *zone)
+{
+    zone->ref_count++;
+    return zone;
+}
+
+void
+gweather_timezone_unref (GWeatherTimezone *zone)
+{
+    if (!--zone->ref_count) {
+	g_free (zone->id);
+	g_free (zone->name);
+	g_slice_free (GWeatherTimezone, zone);
+    }
+}
+
+const char *
+gweather_timezone_get_name (GWeatherTimezone *zone)
+{
+    return zone->name;
+}
+
+const char *
+gweather_timezone_get_tzid (GWeatherTimezone *zone)
+{
+    return zone->id;
+}
+
+int
+gweather_timezone_get_offset (GWeatherTimezone *zone)
+{
+    return zone->offset;
+}
+
+gboolean
+gweather_timezone_has_dst (GWeatherTimezone *zone)
+{
+    return zone->has_dst;
+}
+
+int
+gweather_timezone_get_dst_offset (GWeatherTimezone *zone)
+{
+    g_return_val_if_fail (zone->has_dst, 0);
+    return zone->dst_offset;
+}
+

Added: trunk/libgweather/gweather-timezone.h
==============================================================================
--- (empty file)
+++ trunk/libgweather/gweather-timezone.h	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,44 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* gweather-timezone.c - Timezones
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef __GWEATHER_TIMEZONE_H__
+#define __GWEATHER_TIMEZONE_H__
+
+#ifndef GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#error "libgweather should only be used if you understand that it's subject to change, and is not supported as a fixed API/ABI or as part of the platform"
+#endif
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GWeatherTimezone GWeatherTimezone;
+
+const char       *gweather_timezone_get_name       (GWeatherTimezone *zone);
+const char       *gweather_timezone_get_tzid       (GWeatherTimezone *zone);
+int               gweather_timezone_get_offset     (GWeatherTimezone *zone);
+gboolean          gweather_timezone_has_dst        (GWeatherTimezone *zone);
+int               gweather_timezone_get_dst_offset (GWeatherTimezone *zone);
+
+GWeatherTimezone *gweather_timezone_ref            (GWeatherTimezone *zone);
+void              gweather_timezone_unref          (GWeatherTimezone *zone);
+
+G_END_DECLS
+
+#endif /* __GWEATHER_TIMEZONE_H__ */

Modified: trunk/libgweather/gweather-xml.c
==============================================================================
--- trunk/libgweather/gweather-xml.c	(original)
+++ trunk/libgweather/gweather-xml.c	Mon Aug  4 12:04:12 2008
@@ -18,53 +18,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-
-/* There is very little error checking in the parsing code below, it relies
- * heavily on the locations file being in the correct format.  If you have
- * <name> elements within a parent element, they must come first and be
- * grouped together.
- * The format is as follows:
- *
- * <gweather format="1.0">
- * <region>
- *  <name>Name of the region</name>
- *  <name xml:lang="xx">Translated Name</name>
- *  <name xml:lang="zz">Another Translated Name</name>
- *  <country>
- *   <name>Name of the country</name>
- *   <iso-code>2-letter ISO 3166 code for the country</iso-code>
- *   <tz-hint>default timezone</tz-hint>
- *   <location>
- *    <name>Name of the location</name>
- *    <code>IWIN code</code>
- *    <zone>Forecast code (North America, Australia, UK only)</zone>
- *    <radar>Weather.com radar map code (North America only)</radar>
- *    <coordinates>Latitude and longitude as DD-MM[-SS][H] pair</coordinates>
- *   </location>
- *   <state>
- *     <location>
- *       ....
- *     </location>
- *     <city>
- *      <name>Name of city with multiple locations</city>
- *      <zone>Forecast code</zone>
- *      <radar>Radar Map code</radar>
- *      <location>
- *        ...
- *      </location>
- *     </city>
- *   </state>
- *  </country>
- * </region>
- * <gweather>
- *
- * The thing to note is that each country can either contain different locations
- * or be split into "states" which in turn contain a list of locations.
- *
- * <iso-code> can appear at the country or location level. <tz-hint>
- * can appear at country, state, or location.
- */
-
 #include <string.h>
 #include <math.h>
 #include <locale.h>
@@ -73,375 +26,106 @@
 
 #define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
 #include "gweather-xml.h"
-
-static gint
-gweather_xml_location_sort_func (GtkTreeModel *model, GtkTreeIter *a,
-                                 GtkTreeIter *b, gpointer user_data)
-{
-    gint res;
-    gchar *name_a, *name_b;
-    gchar *fold_a, *fold_b;
-
-    gtk_tree_model_get (model, a, GWEATHER_XML_COL_LOC, &name_a, -1);
-    gtk_tree_model_get (model, b, GWEATHER_XML_COL_LOC, &name_b, -1);
-
-    fold_a = g_utf8_casefold (name_a, -1);
-    fold_b = g_utf8_casefold (name_b, -1);
-
-    res = g_utf8_collate (fold_a, fold_b);
-
-    g_free (name_a);
-    g_free (name_b);
-    g_free (fold_a);
-    g_free (fold_b);
-
-    return res;
-}
-
-static char *
-gweather_xml_get_value (xmlTextReaderPtr xml)
-{
-    char* value;
-
-    /* check for null node */
-    if (xmlTextReaderIsEmptyElement (xml))
-	return NULL;
-
-    /* the next "node" is the text node containing the value we want to get */
-    if (xmlTextReaderRead (xml) != 1)
-	return NULL;
-
-    value = (char *) xmlTextReaderValue (xml);
-
-    /* move on to the end of this node */
-    while (xmlTextReaderNodeType (xml) != XML_READER_TYPE_END_ELEMENT) {
-	if (xmlTextReaderRead (xml) != 1) {
-	    xmlFree (value);
-	    return NULL;
-	}
-    }
-
-    /* consume the end element too */
-    if (xmlTextReaderRead (xml) != 1) {
-	xmlFree (value);
-	return NULL;
-    }
-
-    return value;
-}
-
-static char *
-gweather_xml_parse_name (xmlTextReaderPtr xml)
-{
-    const char * const *locales;
-    const char *this_language;
-    int best_match = INT_MAX;
-    char *lang, *tagname;
-    gboolean keep_going;
-    char *name = NULL;
-    int i;
-
-    locales = g_get_language_names ();
-
-    do {
-	/* First let's get the language */
-	lang = (char *) xmlTextReaderXmlLang (xml);
-
-	if (lang == NULL)
-	    this_language = "C";
-	else
-	    this_language = lang;
-
-	/* the next "node" is text node containing the actual name */
-	if (xmlTextReaderRead (xml) != 1) {
-	    xmlFree (lang);
-	    return NULL;
-	}
-
-	for (i = 0; locales[i] && i < best_match; i++) {
-	    if (!strcmp (locales[i], this_language)) {
-		/* if we've already encounted a less accurate
-		   translation, then free it */
-		xmlFree (name);
-
-		name = (char *) xmlTextReaderValue (xml);
-		best_match = i;
-
-		break;
-	    }
-	}
-
-	xmlFree (lang);
-
-	while (xmlTextReaderNodeType (xml) != XML_READER_TYPE_ELEMENT) {
-	    if (xmlTextReaderRead (xml) != 1) {
-		xmlFree (name);
-		return NULL;
-	    }
-
-	    /* if the next tag is another <name> then keep going */
-	    tagname = (char *) xmlTextReaderName (xml);
-	    keep_going = !strcmp (tagname, "name");
-	    xmlFree (tagname);
-	}
-
-    } while (keep_going);
-
-    return name;
-}
+#include "weather-priv.h"
 
 static gboolean
-gweather_xml_parse_node (xmlTextReaderPtr xml,
-			 GtkTreeStore *store, GtkTreeIter *parent,
-                         const char *dflt_radar, const char *dflt_zone,
-                         const char *dflt_country_code,
-			 const char *dflt_tz_hint, const char *cityname)
+gweather_xml_parse_node (GWeatherLocation *gloc,
+			 GtkTreeStore *store, GtkTreeIter *parent)
 {
-    char *name, *code, *zone, *radar, *coordinates;
-    char *country_code, *tz_hint;
-    char **city, *nocity = NULL;
-    GtkTreeIter iter, *self;
-    gboolean is_location;
-    char *tagname;
-    gboolean ret = FALSE;
-    int tagtype;
-
-    if ((tagname = (char *) xmlTextReaderName (xml)) == NULL)
-	return FALSE;
-
-    if (!strcmp (tagname, "city"))
-	city = &name;
-    else
-	city = &nocity;
-
-    is_location = !strcmp (tagname, "location");
-
-    /* if we're processing the top-level, then don't create a new iter */
-    if (!strcmp (tagname, "gweather"))
-	self = NULL;
-    else {
-	self = &iter;
-	/* insert this node into the tree */
-	gtk_tree_store_append (store, self, parent);
-    }
-
-    xmlFree (tagname);
-
-    coordinates = NULL;
-    radar = NULL;
-    zone = NULL;
-    code = NULL;
-    name = NULL;
-
-    country_code = dflt_country_code ? (char *) xmlStrdup ((xmlChar *) dflt_country_code) : NULL;
-    tz_hint = dflt_tz_hint ? (char *) xmlStrdup ((xmlChar *) dflt_tz_hint) : NULL;
-
-    /* absorb the start tag */
-    if (xmlTextReaderRead (xml) != 1)
-	goto error_out;
-
-    /* start parsing the actual contents of the node */
-    while ((tagtype = xmlTextReaderNodeType (xml)) !=
-	   XML_READER_TYPE_END_ELEMENT) {
-	/* skip non-element types */
-	if (tagtype != XML_READER_TYPE_ELEMENT) {
-	    if (xmlTextReaderRead (xml) != 1)
-		goto error_out;
-
-	    continue;
-	}
-
-	tagname = (char *) xmlTextReaderName (xml);
-
-	if (!strcmp (tagname, "region") || !strcmp (tagname, "country") ||
-	    !strcmp (tagname, "state") || !strcmp (tagname, "city") ||
-	    !strcmp (tagname, "location")) {
-	    /* recursively handle sub-sections */
-	    if (!gweather_xml_parse_node (xml, store, self,
-					  radar, zone, country_code, tz_hint,
-					  *city))
-		goto error_out;
-	} else if (!strcmp (tagname, "name")) {
-	    xmlFree (name);
-	    if ((name = gweather_xml_parse_name (xml)) == NULL)
-		goto error_out;
-	} else if (!strcmp (tagname, "iso-code")) {
-	    xmlFree (country_code);
-	    if ((country_code = gweather_xml_get_value (xml)) == NULL)
-		goto error_out;
-	} else if (!strcmp (tagname, "tz-hint")) {
-	    xmlFree (tz_hint);
-	    if ((tz_hint = gweather_xml_get_value (xml)) == NULL)
-		goto error_out;
-	} else if (!strcmp (tagname, "code")) {
-	    xmlFree (code);
-	    if ((code = gweather_xml_get_value (xml)) == NULL)
-		goto error_out;
-	} else if (!strcmp (tagname, "zone")) {
-	    xmlFree (zone);
-	    if ((zone = gweather_xml_get_value (xml)) == NULL)
-		goto error_out;
-	} else if (!strcmp (tagname, "radar")) {
-	    xmlFree (radar);
-	    if ((radar = gweather_xml_get_value (xml)) == NULL)
-		goto error_out;
-	} else if (!strcmp (tagname, "coordinates")) {
-	    xmlFree (coordinates);
-	    if ((coordinates = gweather_xml_get_value (xml)) == NULL)
-		goto error_out;
-	} else /* some strange tag */ {
-	    /* skip past it (and any children it might have) */
-	    if (xmlTextReaderNext (xml) != 1)
-		goto error_out;
-	}
-
-	xmlFree (tagname);
-    }
-
-    if (self)
-	gtk_tree_store_set (store, self, GWEATHER_XML_COL_LOC, name, -1);
-
-    /* if this is an actual location, setup the WeatherLocation for it */
-    if (is_location) {
-	WeatherLocation *new_loc;
-
-	if (cityname == NULL)
-	    cityname = name;
-
-	if (radar != NULL)
-	    dflt_radar = radar;
-
-	if (zone != NULL)
-	    dflt_zone = zone;
-
-	new_loc =  weather_location_new (cityname, code, dflt_zone,
-					 dflt_radar, coordinates,
-					 country_code, tz_hint);
-
-	gtk_tree_store_set (store, self, GWEATHER_XML_COL_POINTER, new_loc, -1);
-    }
-    /* if this is not a location and there's no child, then it's useless */
-    else if (self && !gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store), self)) {
-	gtk_tree_store_remove (store, self);
-    }
+    GtkTreeIter iter, *self = &iter;
+    GWeatherLocation **children, *parent_loc;
+    GWeatherLocationLevel level;;
+    WeatherLocation *wloc;
+    const char *name;
+    int i;
 
-    /* if this is a city with only one location, then we merge the location and
-     * the city */
-    if (*city) {
-	int n_children;
-
-	n_children = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store),
-						     self);
-	if (n_children == 1) {
-	    GtkTreeIter child;
-	    WeatherLocation *loc;
-
-	    gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, self);
-	    gtk_tree_model_get (GTK_TREE_MODEL (store), &child,
-				GWEATHER_XML_COL_POINTER, &loc, -1);
-	    gtk_tree_store_remove (store, &child);
-	    gtk_tree_store_set (store, self, GWEATHER_XML_COL_POINTER, loc, -1);
+    name = gweather_location_get_name (gloc);
+    children = gweather_location_get_children (gloc);
+    level = gweather_location_get_level (gloc);
+
+    if (!children[0] && level < GWEATHER_LOCATION_WEATHER_STATION) {
+	gweather_location_free_children (gloc, children);
+	return TRUE;
+    }
+
+    switch (gweather_location_get_level (gloc)) {
+    case GWEATHER_LOCATION_WORLD:
+    case GWEATHER_LOCATION_ADM2:
+	self = parent;
+	break;
+
+    case GWEATHER_LOCATION_REGION:
+    case GWEATHER_LOCATION_COUNTRY:
+    case GWEATHER_LOCATION_ADM1:
+	/* Create a row with a name but no WeatherLocation */
+	gtk_tree_store_append (store, &iter, parent);
+	gtk_tree_store_set (store, &iter,
+			    GWEATHER_XML_COL_LOC, name,
+			    -1);
+	break;
+
+    case GWEATHER_LOCATION_CITY:
+	/* If multiple children, treat this like a
+	 * region/country/adm1. If a single child, merge with that
+	 * location.
+	 */
+	gtk_tree_store_append (store, &iter, parent);
+	gtk_tree_store_set (store, &iter,
+			    GWEATHER_XML_COL_LOC, name,
+			    -1);
+	if (children[0] && !children[1]) {
+	    wloc = gweather_location_to_weather_location (children[0], name);
+	    gtk_tree_store_set (store, &iter,
+				GWEATHER_XML_COL_POINTER, wloc,
+				-1);
+	}
+	break;
+
+    case GWEATHER_LOCATION_WEATHER_STATION:
+	gtk_tree_store_append (store, &iter, parent);
+	gtk_tree_store_set (store, &iter,
+			    GWEATHER_XML_COL_LOC, name,
+			    -1);
+
+	parent_loc = gweather_location_get_parent (gloc);
+	if (parent_loc && gweather_location_get_level (parent_loc) == GWEATHER_LOCATION_CITY)
+	    name = gweather_location_get_name (parent_loc);
+	wloc = gweather_location_to_weather_location (gloc, name);
+	gtk_tree_store_set (store, &iter,
+			    GWEATHER_XML_COL_POINTER, wloc,
+			    -1);
+	break;
+    }
+
+    for (i = 0; children[i]; i++) {
+	if (!gweather_xml_parse_node (children[i], store, self)) {
+	    gweather_location_free_children (gloc, children);
+	    return FALSE;
 	}
     }
 
-    /* absorb the end tag.  in the case of processing a <gweather> then 'self'
-       is NULL.  In this case, we let this fail since we might be at EOF */
-    if (xmlTextReaderRead (xml) == 1 || !self)
-	ret = TRUE;
-
-error_out:
-    xmlFree (name);
-    xmlFree (code);
-    xmlFree (zone);
-    xmlFree (radar);
-    xmlFree (coordinates);
-    xmlFree (country_code);
-    xmlFree (tz_hint);
-
-    return ret;
+    gweather_location_free_children (gloc, children);
+    return TRUE;
 }
 
 GtkTreeModel *
 gweather_xml_load_locations (void)
 {
-    const char * const *languages;
-    int i;
-    char *filename;
-    char *tagname, *format;
-    GtkTreeSortable *sortable;
-    GtkTreeStore *store = NULL;
-    xmlTextReaderPtr xml;
-    int keep_going;
-
-    /* First try to load a locale-specific XML. It's much faster. */
-    languages = g_get_language_names ();
-    filename = NULL;
-
-    for (i = 0; languages[i] != NULL; i++) {
-	filename = g_strdup_printf ("%s/Locations.%s.xml",
-				    GWEATHER_XML_LOCATION_DIR, languages[i]);
-
-	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
-	    break;
-
-	g_free (filename);
-	filename = NULL;
-    }
-
-    /* Fallback on the file containing either all translations, or only
-     * the english names (depending on the configure flags). Note that it's
-     * also the file that is advertised in our pkg-config file, so it's
-     * part of the API. */
-    if (!filename)
-	filename = g_strdup (GWEATHER_XML_LOCATION_DIR "/Locations.xml");
-
-    /* Open the xml file containing the different locations */
-    xml = xmlNewTextReaderFilename (filename);
-    g_free (filename);
+    GWeatherLocation *world;
+    GtkTreeStore *store;
 
-    if (xml == NULL)
+    world = gweather_location_new_world (TRUE);
+    if (!world)
 	return NULL;
 
-    /* fast forward to the first element */
-    do {
-	/* if we encounter a problem here, exit right away */
-	if (xmlTextReaderRead (xml) != 1)
-	    goto error_out;
-    } while (xmlTextReaderNodeType (xml) != XML_READER_TYPE_ELEMENT);
-
-    /* check the name and format */
-    tagname = (char *) xmlTextReaderName (xml);
-    keep_going = tagname && !strcmp (tagname, "gweather");
-    xmlFree (tagname);
-
-    if (!keep_going)
-	goto error_out;
-
-    format = (char *) xmlTextReaderGetAttribute (xml, (xmlChar *) "format");
-    keep_going = format && !strcmp (format, "1.0");
-    xmlFree (format);
-
-    if (!keep_going)
-	goto error_out;
-
     store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
 
-    if (!gweather_xml_parse_node (xml, store, NULL, NULL, NULL, NULL, NULL, NULL)) {
+    if (!gweather_xml_parse_node (world, store, NULL)) {
 	g_object_unref (store);
 	store = NULL;
-	goto error_out;
     }
 
-    /* Sort the tree */
-    sortable = GTK_TREE_SORTABLE (store);
-    gtk_tree_sortable_set_default_sort_func (sortable,
-					     &gweather_xml_location_sort_func,
-					     NULL, NULL);
-    gtk_tree_sortable_set_sort_column_id (sortable,
-					  GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
-					  GTK_SORT_ASCENDING);
-error_out:
-    xmlFreeTextReader (xml);
+    gweather_location_unref (world);
 
     return (GtkTreeModel *)store;
 }

Added: trunk/libgweather/location-entry.c
==============================================================================
--- (empty file)
+++ trunk/libgweather/location-entry.c	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,467 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+
+#include <string.h>
+
+G_DEFINE_TYPE (GWeatherLocationEntry, gweather_location_entry, GTK_TYPE_ENTRY)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_LOCATION,
+
+    LAST_PROP
+};
+
+static void gweather_location_entry_build_model (GWeatherLocationEntry *entry,
+						 GWeatherLocation *top);
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+enum
+{
+    GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+    GWEATHER_LOCATION_ENTRY_COL_LOCATION,
+    GWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME,
+    GWEATHER_LOCATION_ENTRY_COL_SORT_NAME,
+    GWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
+
+static gboolean matcher (GtkEntryCompletion *completion, const char *key,
+			 GtkTreeIter *iter, gpointer user_data);
+static gboolean match_selected (GtkEntryCompletion *completion,
+				GtkTreeModel       *model,
+				GtkTreeIter        *iter,
+				gpointer            entry);
+
+static void
+gweather_location_entry_init (GWeatherLocationEntry *entry)
+{
+    GtkEntryCompletion *completion;
+
+    completion = gtk_entry_completion_new ();
+
+    gtk_entry_completion_set_popup_set_width (completion, FALSE);
+    gtk_entry_completion_set_text_column (completion, GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+
+    g_signal_connect (completion, "match_selected",
+		      G_CALLBACK (match_selected), entry);
+
+    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    g_object_unref (completion);
+}
+
+static void
+finalize (GObject *object)
+{
+    GWeatherLocationEntry *entry = GWEATHER_LOCATION_ENTRY (object);
+
+    if (entry->location)
+	gweather_location_unref (entry->location);
+    if (entry->top)
+	gweather_location_unref (entry->top);
+
+    G_OBJECT_CLASS (gweather_location_entry_parent_class)->finalize (object);
+}
+
+static void
+gweather_location_entry_class_init (GWeatherLocationEntryClass *location_entry_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The GWeatherLocation whose children will be used to fill in the entry",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_LOCATION,
+	g_param_spec_pointer ("location",
+			      "Location",
+			      "The selected GWeatherLocation",
+			      G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_TOP:
+	gweather_location_entry_build_model (GWEATHER_LOCATION_ENTRY (object),
+					     g_value_get_pointer (value));
+	break;
+    case PROP_LOCATION:
+	gweather_location_entry_set_location (GWEATHER_LOCATION_ENTRY (object),
+					      g_value_get_pointer (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    GWeatherLocationEntry *entry = GWEATHER_LOCATION_ENTRY (object);
+
+    switch (prop_id) {
+    case PROP_LOCATION:
+	g_value_set_pointer (value, entry->location);
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+set_location_internal (GWeatherLocationEntry *entry,
+		       GtkTreeModel          *model,
+		       GtkTreeIter           *iter)
+{
+    GWeatherLocation *loc;
+    char *name;
+
+    if (entry->location)
+	gweather_location_unref (entry->location);
+
+    if (iter) {
+	gtk_tree_model_get (model, iter,
+			    GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+			    GWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			    -1);
+	entry->location = gweather_location_ref (loc);
+	gtk_entry_set_text (GTK_ENTRY (entry), name);
+	g_free (name);
+    } else {
+	entry->location = NULL;
+	gtk_entry_set_text (GTK_ENTRY (entry), "");
+    }
+
+    gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+    g_object_notify (G_OBJECT (entry), "location");
+}
+
+void
+gweather_location_entry_set_location (GWeatherLocationEntry *entry,
+				      GWeatherLocation      *loc)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    GWeatherLocation *cmploc;
+
+    g_return_if_fail (GWEATHER_IS_LOCATION_ENTRY (entry));
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    GWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+	if (loc == cmploc) {
+	    set_location_internal (entry, model, &iter);
+	    return;
+	}
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+GWeatherLocation *
+gweather_location_entry_get_location (GWeatherLocationEntry *entry)
+{
+    g_return_val_if_fail (GWEATHER_IS_LOCATION_ENTRY (entry), NULL);
+
+    if (entry->location)
+	return gweather_location_ref (entry->location);
+    else
+	return NULL;
+}
+
+void
+gweather_location_entry_set_city (GWeatherLocationEntry *entry,
+				  const char            *city_name,
+				  const char            *code)
+{
+    GtkEntryCompletion *completion;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    GWeatherLocation *cmploc;
+    const char *cmpcode;
+    char *cmpname;
+
+    g_return_if_fail (GWEATHER_IS_LOCATION_ENTRY (entry));
+    g_return_if_fail (code != NULL);
+
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    model = gtk_entry_completion_get_model (completion);
+
+    gtk_tree_model_get_iter_first (model, &iter);
+    do {
+	gtk_tree_model_get (model, &iter,
+			    GWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+			    -1);
+
+	cmpcode = gweather_location_get_code (cmploc);
+	if (!cmpcode || strcmp (cmpcode, code) != 0)
+	    continue;
+
+	if (city_name) {
+	    cmpname = gweather_location_get_city_name (cmploc);
+	    if (!cmpname || strcmp (cmpname, city_name) != 0) {
+		g_free (cmpname);
+		continue;
+	    }
+	    g_free (cmpname);
+	}
+
+	set_location_internal (entry, model, &iter);
+	return;
+    } while (gtk_tree_model_iter_next (model, &iter));
+
+    set_location_internal (entry, model, NULL);
+}
+
+static void
+fill_location_entry_model (GtkTreeStore *store, GWeatherLocation *loc,
+			   const char *parent_display_name,
+			   const char *parent_compare_name)
+{
+    GWeatherLocation **children;
+    char *display_name, *compare_name;
+    GtkTreeIter iter;
+    int i;
+
+    children = gweather_location_get_children (loc);
+
+    switch (gweather_location_get_level (loc)) {
+    case GWEATHER_LOCATION_WORLD:
+    case GWEATHER_LOCATION_REGION:
+    case GWEATHER_LOCATION_ADM2:
+	/* Ignore these levels of hierarchy; just recurse, passing on
+	 * the names from the parent node.
+	 */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       parent_display_name,
+				       parent_compare_name);
+	}
+	break;
+
+    case GWEATHER_LOCATION_COUNTRY:
+	/* Recurse, initializing the names to the country name */
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       gweather_location_get_name (loc),
+				       gweather_location_get_sort_name (loc));
+	}
+	break;
+
+    case GWEATHER_LOCATION_ADM1:
+	/* Recurse, adding the ADM1 name to the country name */
+	display_name = g_strdup_printf ("%s, %s", gweather_location_get_name (loc), parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s", gweather_location_get_sort_name (loc), parent_compare_name);
+
+	for (i = 0; children[i]; i++) {
+	    fill_location_entry_model (store, children[i],
+				       display_name, compare_name);
+	}
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+
+    case GWEATHER_LOCATION_CITY:
+	/* If there are multiple (<location>) children, add a line for
+	 * each of them.
+	 */
+	if (children[1]) {
+	    for (i = 0; children[i]; i++) {
+		display_name = g_strdup_printf ("%s (%s), %s",
+						gweather_location_get_name (loc),
+						gweather_location_get_name (children[i]),
+						parent_display_name);
+		compare_name = g_strdup_printf ("%s (%s), %s",
+						gweather_location_get_sort_name (loc),
+						gweather_location_get_sort_name (children[i]),
+						parent_compare_name);
+
+		gtk_tree_store_append (store, &iter, NULL);
+		gtk_tree_store_set (store, &iter,
+				    GWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+				    GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+				    GWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+				    -1);
+
+		g_free (display_name);
+		g_free (compare_name);
+	    }
+	    break;
+	}
+	/* else, if there's only a single location, fall through */
+
+    case GWEATHER_LOCATION_WEATHER_STATION:
+	/* <location> with no parent <city>, or <city> with a single
+	 * child <location>.
+	 */
+	display_name = g_strdup_printf ("%s, %s",
+					gweather_location_get_name (loc),
+					parent_display_name);
+	compare_name = g_strdup_printf ("%s, %s",
+					gweather_location_get_sort_name (loc),
+					parent_compare_name);
+
+	gtk_tree_store_append (store, &iter, NULL);
+	gtk_tree_store_set (store, &iter,
+			    GWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+			    GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+			    GWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, compare_name,
+			    -1);
+
+	g_free (display_name);
+	g_free (compare_name);
+	break;
+    }
+
+    gweather_location_free_children (loc, children);
+}
+
+static void
+gweather_location_entry_build_model (GWeatherLocationEntry *entry,
+				     GWeatherLocation *top)
+{
+    GtkTreeStore *store = NULL;
+
+    entry->top = gweather_location_ref (top);
+
+    store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+    fill_location_entry_model (store, top, NULL, NULL);
+    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
+				    GTK_TREE_MODEL (store));
+    g_object_unref (store);
+}
+
+static char *
+find_word (const char *full_name, const char *word, int word_len,
+	   gboolean whole_word, gboolean is_first_word)
+{
+    char *p = (char *)full_name - 1;
+
+    while ((p = strchr (p + 1, *word))) {
+	if (strncmp (p, word, word_len) != 0)
+	    continue;
+
+	if (p > (char *)full_name) {
+	    char *prev = g_utf8_prev_char (p);
+
+	    /* Make sure p points to the start of a word */
+	    if (g_unichar_isalpha (g_utf8_get_char (prev)))
+		continue;
+
+	    /* If we're matching the first word of the key, it has to
+	     * match the first word of the location, city, state, or
+	     * country. Eg, it either matches the start of the string
+	     * (which we already know it doesn't at this point) or
+	     * it is preceded by the string ", " (which isn't actually
+	     * a perfect test. FIXME)
+	     */
+	    if (is_first_word) {
+		if (prev == (char *)full_name || strncmp (prev - 1, ", ", 2) != 0)
+		    continue;
+	    }
+	}
+
+	if (whole_word && g_unichar_isalpha (g_utf8_get_char (p + word_len)))
+	    continue;
+
+	return p;
+    }
+    return NULL;
+}
+
+static gboolean
+matcher (GtkEntryCompletion *completion, const char *key,
+	 GtkTreeIter *iter, gpointer user_data)
+{
+    char *name, *name_mem;
+    GWeatherLocation *loc;
+    gboolean is_first_word = TRUE, match;
+    int len;
+
+    gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
+			GWEATHER_LOCATION_ENTRY_COL_COMPARE_NAME, &name_mem,
+			GWEATHER_LOCATION_ENTRY_COL_LOCATION, &loc,
+			-1);
+    name = name_mem;
+
+    if (!loc) {
+	g_free (name_mem);
+	return FALSE;
+    }
+
+    /* All but the last word in KEY must match a full word from NAME,
+     * in order (but possibly skipping some words from NAME).
+     */
+    len = strcspn (key, " ");
+    while (key[len]) {
+	name = find_word (name, key, len, TRUE, is_first_word);
+	if (!name) {
+	    g_free (name_mem);
+	    return FALSE;
+	}
+
+	key += len;
+	while (*key && !g_unichar_isalpha (g_utf8_get_char (key)))
+	    key = g_utf8_next_char (key);
+	while (*name && !g_unichar_isalpha (g_utf8_get_char (name)))
+	    name = g_utf8_next_char (name);
+
+	len = strcspn (key, " ");
+	is_first_word = FALSE;
+    }
+
+    /* The last word in KEY must match a prefix of a following word in NAME */
+    match = find_word (name, key, strlen (key), FALSE, is_first_word) != NULL;
+    g_free (name_mem);
+    return match;
+}
+
+static gboolean
+match_selected (GtkEntryCompletion *completion,
+		GtkTreeModel       *model,
+		GtkTreeIter        *iter,
+		gpointer            entry)
+{
+    set_location_internal (entry, model, iter);
+    return TRUE;
+}
+
+GtkWidget *
+gweather_location_entry_new (GWeatherLocation *top)
+{
+    return g_object_new (GWEATHER_TYPE_LOCATION_ENTRY,
+			 "top", top,
+			 NULL);
+}

Added: trunk/libgweather/location-entry.h
==============================================================================
--- (empty file)
+++ trunk/libgweather/location-entry.h	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#ifndef GWEATHER_LOCATION_ENTRY_H
+#define GWEATHER_LOCATION_ENTRY_H 1
+
+#include <gtk/gtk.h>
+#include <libgweather/gweather-location.h>
+
+#define GWEATHER_TYPE_LOCATION_ENTRY            (gweather_location_entry_get_type ())
+#define GWEATHER_LOCATION_ENTRY(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), GWEATHER_TYPE_LOCATION_ENTRY, GWeatherLocationEntry))
+#define GWEATHER_LOCATION_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GWEATHER_TYPE_LOCATION_ENTRY, GWeatherLocationEntryClass))
+#define GWEATHER_IS_LOCATION_ENTRY(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), GWEATHER_TYPE_LOCATION_ENTRY))
+#define GWEATHER_IS_LOCATION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GWEATHER_TYPE_LOCATION_ENTRY))
+#define GWEATHER_LOCATION_ENTRY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GWEATHER_TYPE_LOCATION_ENTRY, GWeatherLocationEntryClass))
+
+typedef struct {
+    GtkEntry parent;
+
+    /*< private >*/
+    GWeatherLocation *location, *top;
+} GWeatherLocationEntry;
+
+typedef struct {
+    GtkEntryClass parent_class;
+
+} GWeatherLocationEntryClass;
+
+GType             gweather_location_entry_get_type     (void);
+
+GtkWidget        *gweather_location_entry_new          (GWeatherLocation      *top);
+
+void              gweather_location_entry_set_location (GWeatherLocationEntry *entry,
+							GWeatherLocation      *loc);
+GWeatherLocation *gweather_location_entry_get_location (GWeatherLocationEntry *entry);
+
+void              gweather_location_entry_set_city     (GWeatherLocationEntry *entry,
+							const char            *city_name,
+							const char            *code);
+
+#endif

Added: trunk/libgweather/parser.c
==============================================================================
--- (empty file)
+++ trunk/libgweather/parser.c	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,222 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "parser.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libxml/xmlreader.h>
+
+/**
+ * gweather_parser_get_value:
+ * @parser: a #GWeatherParser
+ *
+ * Gets the text of the element whose start tag @parser is pointing to.
+ * Leaves @parser pointing at the next node after the element's end tag.
+ *
+ * Return value: the text of the current node, as a libxml-allocated
+ * string, or %NULL if the node is empty.
+ **/
+char *
+gweather_parser_get_value (GWeatherParser *parser)
+{
+    char *value;
+
+    /* check for null node */
+    if (xmlTextReaderIsEmptyElement (parser->xml))
+	return NULL;
+
+    /* the next "node" is the text node containing the value we want to get */
+    if (xmlTextReaderRead (parser->xml) != 1)
+	return NULL;
+
+    value = (char *) xmlTextReaderValue (parser->xml);
+
+    /* move on to the end of this node */
+    while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    xmlFree (value);
+	    return NULL;
+	}
+    }
+
+    /* consume the end element too */
+    if (xmlTextReaderRead (parser->xml) != 1) {
+	xmlFree (value);
+	return NULL;
+    }
+
+    return value;
+}
+
+/**
+ * gweather_parser_get_localized_value:
+ * @parser: a #GWeatherParser
+ *
+ * Looks at the name of the element @parser is currently pointing to, and
+ * returns the content of either that node, or a following node with
+ * the same name but an "xml:lang" attribute naming one of the locale
+ * languages. Leaves @parser pointing to the next node after the last
+ * consecutive element with the same name as the original element.
+ *
+ * Return value: the localized (or unlocalized) text, as a
+ * libxml-allocated string, or %NULL if the node is empty.
+ **/
+char *
+gweather_parser_get_localized_value (GWeatherParser *parser)
+{
+    const char *this_language;
+    int best_match = INT_MAX;
+    const char *lang, *tagname, *next_tagname;
+    gboolean keep_going;
+    char *name = NULL;
+    int i;
+
+    tagname = (const char *) xmlTextReaderConstName (parser->xml);
+
+    do {
+	/* First let's get the language */
+	lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
+
+	if (lang == NULL)
+	    this_language = "C";
+	else
+	    this_language = lang;
+
+	/* the next "node" is text node containing the actual name */
+	if (xmlTextReaderRead (parser->xml) != 1) {
+	    if (name)
+		xmlFree (name);
+	    return NULL;
+	}
+
+	for (i = 0; parser->locales[i] && i < best_match; i++) {
+	    if (!strcmp (parser->locales[i], this_language)) {
+		/* if we've already encounted a less accurate
+		   translation, then free it */
+		g_free (name);
+
+		name = (char *) xmlTextReaderValue (parser->xml);
+		best_match = i;
+
+		break;
+	    }
+	}
+
+	/* Skip to close tag */
+	while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	}
+
+	/* Skip junk */
+	do {
+	    if (xmlTextReaderRead (parser->xml) != 1) {
+		xmlFree (name);
+		return NULL;
+	    }
+	} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
+		 xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
+
+	/* if the next tag has the same name then keep going */
+	next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
+	keep_going = !strcmp (next_tagname, tagname);
+
+    } while (keep_going);
+
+    return name;
+}
+
+GWeatherParser *
+gweather_parser_new (gboolean use_regions)
+{
+    GWeatherParser *parser;
+    int i, keep_going;
+    char *filename;
+    char *tagname, *format;
+    time_t now;
+    struct tm tm;
+
+    parser = g_slice_new0 (GWeatherParser);
+    parser->use_regions = use_regions;
+    parser->locales = g_get_language_names ();
+
+    /* First try to load a locale-specific XML. It's much faster. */
+    filename = NULL;
+    for (i = 0; parser->locales[i] != NULL; i++) {
+	filename = g_strdup_printf ("%s/Locations.%s.xml",
+				    GWEATHER_XML_LOCATION_DIR,
+				    parser->locales[i]);
+
+	if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+	    break;
+
+	g_free (filename);
+	filename = NULL;
+    }
+
+    /* Fall back on the file containing either all translations, or only
+     * the english names (depending on the configure flags).
+     */
+    if (!filename)
+	filename = g_strdup (GWEATHER_XML_LOCATION_DIR "/Locations.xml");
+
+    /* Open the xml file containing the different locations */
+    parser->xml = xmlNewTextReaderFilename (filename);
+    g_free (filename);
+
+    if (parser->xml == NULL)
+	goto error_out;
+
+    /* fast forward to the first element */
+    do {
+	/* if we encounter a problem here, exit right away */
+	if (xmlTextReaderRead (parser->xml) != 1)
+	    goto error_out;
+    } while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
+
+    /* check the name and format */
+    tagname = (char *) xmlTextReaderName (parser->xml);
+    keep_going = tagname && !strcmp (tagname, "gweather");
+    xmlFree (tagname);
+
+    if (!keep_going)
+	goto error_out;
+
+    format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
+    keep_going = format && !strcmp (format, "1.0");
+    xmlFree (format);
+
+    if (!keep_going)
+	goto error_out;
+
+    /* Get timestamps for the start and end of this year */
+    now = time (NULL);
+    tm = *gmtime (&now);
+    tm.tm_mon = 0;
+    tm.tm_mday = 1;
+    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    parser->year_start = mktime (&tm);
+    tm.tm_year++;
+    parser->year_end = mktime (&tm);
+
+    return parser;
+
+error_out:
+    gweather_parser_free (parser);
+    return NULL;
+}
+
+void
+gweather_parser_free (GWeatherParser *parser)
+{
+    if (parser->xml)
+	xmlFreeTextReader (parser->xml);
+    g_slice_free (GWeatherParser, parser);
+}

Added: trunk/libgweather/parser.h
==============================================================================
--- (empty file)
+++ trunk/libgweather/parser.h	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,25 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#ifndef GWEATHER_PARSER_H
+#define GWEATHER_PARSER_H 1
+
+#include <libxml/xmlreader.h>
+#include "gweather-timezone.h"
+
+typedef struct {
+    xmlTextReaderPtr xml;
+    const char * const *locales;
+    gboolean use_regions;
+    time_t year_start, year_end;
+} GWeatherParser;
+
+GWeatherParser *gweather_parser_new                 (gboolean        use_regions);
+void            gweather_parser_free                (GWeatherParser *parser);
+
+char           *gweather_parser_get_value           (GWeatherParser *parser);
+char           *gweather_parser_get_localized_value (GWeatherParser *parser);
+
+/* from gweather-timezone.c */
+GWeatherTimezone **gweather_timezones_parse_xml (GWeatherParser *parser);
+
+#endif

Added: trunk/libgweather/test_locations.c
==============================================================================
--- (empty file)
+++ trunk/libgweather/test_locations.c	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,65 @@
+
+#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "location-entry.h"
+#include "timezone-menu.h"
+
+static void
+deleted (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+    gtk_main_quit ();
+}
+
+static void
+location_changed (GObject *object, GParamSpec *param, gpointer tzmenu)
+{
+    GWeatherLocationEntry *entry = GWEATHER_LOCATION_ENTRY (object);
+    GWeatherLocation *loc;
+    GWeatherTimezone *zone;
+
+    loc = gweather_location_entry_get_location (entry);
+    g_return_if_fail (loc != NULL);
+    zone = gweather_location_get_timezone (loc);
+    if (zone)
+	gweather_timezone_menu_set_tzid (tzmenu, gweather_timezone_get_tzid (zone));
+    else
+	gweather_timezone_menu_set_tzid (tzmenu, NULL);
+    if (zone)
+	gweather_timezone_unref (zone);
+    gweather_location_unref (loc);
+}
+
+int
+main (int argc, char **argv)
+{
+    GWeatherLocation *loc;
+    GtkWidget *window, *vbox, *entry;
+    GtkWidget *combo;
+    gtk_init (&argc, &argv);
+
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title (GTK_WINDOW (window), "location");
+    gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+    g_signal_connect (window, "delete-event",
+		      G_CALLBACK (deleted), NULL);
+
+    vbox = gtk_vbox_new (FALSE, 8);
+    gtk_container_add (GTK_CONTAINER (window), vbox);
+
+    loc = gweather_location_new_world (FALSE);
+    entry = gweather_location_entry_new (loc);
+    gtk_widget_set_size_request (entry, 400, -1);
+    gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, TRUE, 0);
+
+    combo = gweather_timezone_menu_new (loc);
+    gweather_location_unref (loc);
+    gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, TRUE, 0);
+
+    g_signal_connect (entry, "notify::location",
+		      G_CALLBACK (location_changed), combo);
+
+    gtk_widget_show_all (window);
+
+    gtk_main ();
+
+    return 0;
+}

Added: trunk/libgweather/timezone-menu.c
==============================================================================
--- (empty file)
+++ trunk/libgweather/timezone-menu.c	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,346 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "timezone-menu.h"
+
+#include <string.h>
+
+G_DEFINE_TYPE (GWeatherTimezoneMenu, gweather_timezone_menu, GTK_TYPE_COMBO_BOX)
+
+enum {
+    PROP_0,
+
+    PROP_TOP,
+    PROP_TZID,
+
+    LAST_PROP
+};
+
+static void set_property (GObject *object, guint prop_id,
+			  const GValue *value, GParamSpec *pspec);
+static void get_property (GObject *object, guint prop_id,
+			  GValue *value, GParamSpec *pspec);
+
+static void changed      (GtkComboBox *combo);
+
+static GtkTreeModel *gweather_timezone_model_new (GWeatherLocation *top);
+static gboolean row_separator_func (GtkTreeModel *model, GtkTreeIter *iter,
+				    gpointer data);
+static void is_sensitive (GtkCellLayout *cell_layout, GtkCellRenderer *cell,
+			  GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data);
+
+static void
+gweather_timezone_menu_init (GWeatherTimezoneMenu *menu)
+{
+    GtkCellRenderer *renderer;
+
+    gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (menu),
+					  row_separator_func, NULL, NULL);
+
+    renderer = gtk_cell_renderer_text_new ();
+    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (menu), renderer, TRUE);
+    gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (menu), renderer,
+				    "markup", 0,
+				    NULL);
+    gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (menu),
+					renderer, is_sensitive, NULL, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+    GWeatherTimezoneMenu *menu = GWEATHER_TIMEZONE_MENU (object);
+
+    if (menu->zone)
+	gweather_timezone_unref (menu->zone);
+
+    G_OBJECT_CLASS (gweather_timezone_menu_parent_class)->finalize (object);
+}
+
+static void
+gweather_timezone_menu_class_init (GWeatherTimezoneMenuClass *timezone_menu_class)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (timezone_menu_class);
+    GtkComboBoxClass *combo_class = GTK_COMBO_BOX_CLASS (timezone_menu_class);
+
+    object_class->finalize = finalize;
+    object_class->set_property = set_property;
+    object_class->get_property = get_property;
+
+    combo_class->changed = changed;
+
+    /* properties */
+    g_object_class_install_property (
+	object_class, PROP_TOP,
+	g_param_spec_pointer ("top",
+			      "Top Location",
+			      "The GWeatherLocation whose children will be used to fill in the menu",
+			      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property (
+	object_class, PROP_TZID,
+	g_param_spec_string ("tzid",
+			     "TZID",
+			     "The selected TZID",
+			     NULL,
+			     G_PARAM_READWRITE));
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    GtkTreeModel *model;
+
+    switch (prop_id) {
+    case PROP_TOP:
+	model = gweather_timezone_model_new (g_value_get_pointer (value));
+	gtk_combo_box_set_model (GTK_COMBO_BOX (object), model);
+	g_object_unref (model);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (object), 0);
+	break;
+
+    case PROP_TZID:
+	gweather_timezone_menu_set_tzid (GWEATHER_TIMEZONE_MENU (object),
+					 g_value_get_string (value));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+	      GValue *value, GParamSpec *pspec)
+{
+    GWeatherTimezoneMenu *menu = GWEATHER_TIMEZONE_MENU (object);
+
+    switch (prop_id) {
+    case PROP_TZID:
+	g_value_set_string (value, gweather_timezone_menu_get_tzid (menu));
+	break;
+    default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	break;
+    }
+}
+
+enum {
+    GWEATHER_TIMEZONE_MENU_NAME,
+    GWEATHER_TIMEZONE_MENU_ZONE
+};
+
+static void
+changed (GtkComboBox *combo)
+{
+    GWeatherTimezoneMenu *menu = GWEATHER_TIMEZONE_MENU (combo);
+    GtkTreeIter iter;
+
+    if (menu->zone)
+	gweather_timezone_unref (menu->zone);
+
+    gtk_combo_box_get_active_iter (combo, &iter);
+    gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
+			GWEATHER_TIMEZONE_MENU_ZONE, &menu->zone,
+			-1);
+
+    if (menu->zone)
+	gweather_timezone_ref (menu->zone);
+
+    g_object_notify (G_OBJECT (combo), "tzid");
+}
+
+static void
+append_offset (GString *desc, int offset)
+{
+    int hours, minutes;
+
+    hours = offset / 60;
+    minutes = (offset > 0) ? offset % 60 : -offset % 60;
+
+    if (minutes)
+	g_string_append_printf (desc, "GMT%+d:%02d", hours, minutes);
+    else if (hours)
+	g_string_append_printf (desc, "GMT%+d", hours);
+    else
+	g_string_append (desc, "GMT");
+}
+
+static char *
+get_offset (GWeatherTimezone *zone)
+{
+    GString *desc;
+
+    desc = g_string_new (NULL);
+    append_offset (desc, gweather_timezone_get_offset (zone));
+    if (gweather_timezone_has_dst (zone)) {
+	g_string_append (desc, " / ");
+	append_offset (desc, gweather_timezone_get_dst_offset (zone));
+    }
+    return g_string_free (desc, FALSE);
+}
+
+static void
+insert_locations (GtkTreeStore *store, GWeatherLocation *loc)
+{
+    int i;
+
+    if (gweather_location_get_level (loc) < GWEATHER_LOCATION_COUNTRY) {
+	GWeatherLocation **children;
+
+	children = gweather_location_get_children (loc);
+	for (i = 0; children[i]; i++)
+	    insert_locations (store, children[i]);
+	gweather_location_free_children (loc, children);
+    } else {
+	GWeatherTimezone **zones;
+	GtkTreeIter iter, ziter;
+	char *name, *offset;
+
+	zones = gweather_location_get_timezones (loc);
+	if (zones[1]) {
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				GWEATHER_TIMEZONE_MENU_NAME, gweather_location_get_name (loc),
+				-1);
+
+	    for (i = 0; zones[i]; i++) {
+		offset = get_offset (zones[i]);
+		name = g_strdup_printf ("%s <small>(%s)</small>",
+					gweather_timezone_get_name (zones[i]),
+					offset);
+		gtk_tree_store_append (store, &ziter, &iter);
+		gtk_tree_store_set (store, &ziter,
+				    GWEATHER_TIMEZONE_MENU_NAME, name,
+				    GWEATHER_TIMEZONE_MENU_ZONE, gweather_timezone_ref (zones[i]),
+				    -1);
+		g_free (name);
+		g_free (offset);
+	    }
+	} else if (zones[0]) {
+	    offset = get_offset (zones[0]);
+	    name = g_strdup_printf ("%s <small>(%s)</small>",
+				    gweather_location_get_name (loc),
+				    offset);
+	    gtk_tree_store_append (store, &iter, NULL);
+	    gtk_tree_store_set (store, &iter,
+				GWEATHER_TIMEZONE_MENU_NAME, name,
+				GWEATHER_TIMEZONE_MENU_ZONE, gweather_timezone_ref (zones[0]),
+				-1);
+	    g_free (name);
+	    g_free (offset);
+	}
+
+	gweather_location_free_timezones (loc, zones);
+    }
+}
+
+static GtkTreeModel *
+gweather_timezone_model_new (GWeatherLocation *top)
+{
+    GtkTreeStore *store;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+
+    store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+    model = GTK_TREE_MODEL (store);
+
+    gtk_tree_store_append (store, &iter, NULL);
+    gtk_tree_store_set (store, &iter,
+			GWEATHER_TIMEZONE_MENU_NAME, "<i>Unknown</i>",
+			GWEATHER_TIMEZONE_MENU_ZONE, NULL,
+			-1);
+    gtk_tree_store_append (store, &iter, NULL);
+
+    insert_locations (store, top);
+
+    return model;
+}
+
+static gboolean
+row_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+{
+    char *name;
+
+    gtk_tree_model_get (model, iter,
+			GWEATHER_TIMEZONE_MENU_NAME, &name,
+			-1);
+    if (name) {
+	g_free (name);
+	return FALSE;
+    } else
+	return TRUE;
+}
+
+static void
+is_sensitive (GtkCellLayout *cell_layout, GtkCellRenderer *cell,
+	      GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+    gboolean sensitive;
+
+    sensitive = !gtk_tree_model_iter_has_child (tree_model, iter);
+    g_object_set (cell, "sensitive", sensitive, NULL);
+}
+
+GtkWidget *
+gweather_timezone_menu_new (GWeatherLocation *top)
+{
+    return g_object_new (GWEATHER_TYPE_TIMEZONE_MENU,
+			 "top", top,
+			 NULL);
+}
+
+typedef struct {
+    GtkComboBox *combo;
+    const char  *tzid;
+} SetTimezoneData;
+
+static gboolean
+check_tzid (GtkTreeModel *model, GtkTreePath *path,
+	    GtkTreeIter *iter, gpointer data)
+{
+    SetTimezoneData *tzd = data;
+    GWeatherTimezone *zone;
+
+    gtk_tree_model_get (model, iter,
+			GWEATHER_TIMEZONE_MENU_ZONE, &zone,
+			-1);
+    if (!zone)
+	return FALSE;
+
+    if (!strcmp (gweather_timezone_get_tzid (zone), tzd->tzid)) {
+	gtk_combo_box_set_active_iter (tzd->combo, iter);
+	return TRUE;
+    } else
+	return FALSE;
+}
+
+void
+gweather_timezone_menu_set_tzid (GWeatherTimezoneMenu *menu,
+				 const char           *tzid)
+{
+    SetTimezoneData tzd;
+
+    if (!tzid) {
+	gtk_combo_box_set_active (GTK_COMBO_BOX (menu), 0);
+	return;
+    }
+
+    tzd.combo = GTK_COMBO_BOX (menu);
+    tzd.tzid = tzid;
+    gtk_tree_model_foreach (gtk_combo_box_get_model (tzd.combo),
+			    check_tzid, &tzd);
+}
+
+const char *
+gweather_timezone_menu_get_tzid (GWeatherTimezoneMenu *menu)
+{
+    if (!menu->zone)
+	return NULL;
+    return gweather_timezone_get_tzid (menu->zone);
+}
+

Added: trunk/libgweather/timezone-menu.h
==============================================================================
--- (empty file)
+++ trunk/libgweather/timezone-menu.h	Mon Aug  4 12:04:12 2008
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#ifndef GWEATHER_TIMEZONE_MENU_H
+#define GWEATHER_TIMEZONE_MENU_H 1
+
+#include <gtk/gtk.h>
+#include <libgweather/gweather-location.h>
+
+#define GWEATHER_TYPE_TIMEZONE_MENU            (gweather_timezone_menu_get_type ())
+#define GWEATHER_TIMEZONE_MENU(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), GWEATHER_TYPE_TIMEZONE_MENU, GWeatherTimezoneMenu))
+#define GWEATHER_TIMEZONE_MENU_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GWEATHER_TYPE_TIMEZONE_MENU, GWeatherTimezoneMenuClass))
+#define GWEATHER_IS_TIMEZONE_MENU(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), GWEATHER_TYPE_TIMEZONE_MENU))
+#define GWEATHER_IS_TIMEZONE_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GWEATHER_TYPE_TIMEZONE_MENU))
+#define GWEATHER_TIMEZONE_MENU_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GWEATHER_TYPE_TIMEZONE_MENU, GWeatherTimezoneMenuClass))
+
+typedef struct {
+    GtkComboBox parent;
+
+    /*< private >*/
+    GWeatherTimezone *zone;
+} GWeatherTimezoneMenu;
+
+typedef struct {
+    GtkComboBoxClass parent_class;
+
+} GWeatherTimezoneMenuClass;
+
+GType       gweather_timezone_menu_get_type         (void);
+
+GtkWidget  *gweather_timezone_menu_new              (GWeatherLocation     *top);
+
+void        gweather_timezone_menu_set_tzid         (GWeatherTimezoneMenu *menu,
+						     const char           *tzid);
+const char *gweather_timezone_menu_get_tzid         (GWeatherTimezoneMenu *menu);
+
+#endif

Modified: trunk/libgweather/weather-priv.h
==============================================================================
--- trunk/libgweather/weather-priv.h	(original)
+++ trunk/libgweather/weather-priv.h	Mon Aug  4 12:04:12 2008
@@ -16,6 +16,12 @@
 #include <libsoup/soup.h>
 
 #include "weather.h"
+#include "gweather-location.h"
+
+#define WEATHER_LOCATION_CODE_LEN 4
+
+WeatherLocation *gweather_location_to_weather_location (GWeatherLocation *gloc,
+							const char *name);
 
 /*
  * Weather information.

Modified: trunk/libgweather/weather.h
==============================================================================
--- trunk/libgweather/weather.h	(original)
+++ trunk/libgweather/weather.h	Mon Aug  4 12:04:12 2008
@@ -29,8 +29,6 @@
  * Location
  */
 
-#define WEATHER_LOCATION_CODE_LEN 4
-
 struct _WeatherLocation {
     gchar *name;
     gchar *code;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]