Ticket #2245: Link from /browse/* pages to the wiki key/value pages
authorÆvar Arnfjörð Bjarmason <avarab@gmail.com>
Tue, 20 Apr 2010 12:55:14 +0000 (12:55 +0000)
committerÆvar Arnfjörð Bjarmason <avarab@gmail.com>
Tue, 20 Apr 2010 12:55:14 +0000 (12:55 +0000)
app/helpers/browse_helper.rb
app/views/browse/_tag.html.erb
config/locales/en.yml
config/wiki-tag-and-key-description.yml [new file with mode: 0644]
script/misc/update-key-and-tag-description-pages-from-wiki [new file with mode: 0644]

index aed0c51..e252e30 100644 (file)
@@ -15,4 +15,42 @@ module BrowseHelper
     end
     return name
   end
+
+  def wiki_link(type, key, tag)
+    wiki_data = YAML.load_file("#{RAILS_ROOT}/config/wiki-tag-and-key-description.yml")
+    my_locale = I18n.locale.to_s
+
+    if type == "key"
+      ret = key
+      lookup = key
+    else
+      ret = tag
+      lookup = key + "=" + tag
+    end
+
+    # Try our native language
+    has_primary = wiki_data[my_locale][type][lookup] rescue false
+    if has_primary
+      ret = wikify(type, key, tag, lookup, wiki_data[my_locale][type][lookup])
+    else
+      # Fall back on English
+      has_fallback = wiki_data["en"][type][lookup] rescue false
+      if has_fallback
+        ret = wikify(type, key, tag, lookup, wiki_data["en"][type][lookup])
+      end
+    end
+
+    return ret
+  end
+
+  def wikify(type, key, tag, text, wiki)
+    my_locale = I18n.locale
+    url = "http://wiki.openstreetmap.org/index.php?title=#{wiki}&uselang=#{my_locale}"
+    
+    if type == "key"
+      return '<a href="' + url + '" title="' + h(t('browse.tag_details.wiki_link.key', :key => key)) + '">' + h(text) + '</a>'
+    else
+      return '<a href="' + url + '" title="' + h(t('browse.tag_details.wiki_link.tag', :key => key, :value => tag)) + '">' + h(tag) + '</a>'
+    end
+  end
 end
index ab5707f..4096873 100644 (file)
@@ -1,3 +1,3 @@
 <tr>
-  <td><%= h(tag[0]) %> = <%= linkify(h(tag[1])) %></td>
+  <td><%= wiki_link("key", h(tag[0]), nil) %> = <%= wiki_link("tag", h(tag[0]), auto_link(h(tag[1]))) %></td>
 </tr> 
index 8699d60..17bae6c 100644 (file)
@@ -233,6 +233,9 @@ en:
             # There is no 'relation' type because it is not represented in OpenLayers
     tag_details:
       tags: "Tags:"
+      wiki_link:
+        key: "The wiki description page for the {{key}}=* tag"
+        tag: "The wiki description page for the {{key}}={{value}} tag"
     way_details:
       nodes: "Nodes:"
       part_of: "Part of:"
diff --git a/config/wiki-tag-and-key-description.yml b/config/wiki-tag-and-key-description.yml
new file mode 100644 (file)
index 0000000..832de07
--- /dev/null
@@ -0,0 +1,564 @@
+# THIS FILE IS AUTOGENERATED WITH THE script/misc/update-key-and-tag-description-pages-from-wiki
+# PROGRAM DO NOT MANUALLY EDIT IT
+
+---
+cz:
+  key:
+    historic: Cz:Key:historic
+    railway: Cz:Key:railway
+de:
+  key:
+    abutters: DE:Key:abutters
+    access: DE:Key:access
+    addr: DE:Key:addr
+    aerialway: DE:Key:aerialway
+    aeroway: DE:Key:aeroway
+    amenity: DE:Key:amenity
+    barrier: DE:Key:barrier
+    basin: DE:Key:basin
+    bridge: DE:Key:bridge
+    building: DE:Key:building
+    comment: DE:Key:comment
+    crossing: DE:Key:crossing
+    cycleway: DE:Key:cycleway
+    denomination: DE:Key:denomination
+    description: DE:Key:description
+    disused: DE:Key:disused
+    drink: DE:Key:drink
+    embankment: DE:Key:embankment
+    fixme: DE:Key:fixme
+    geological: DE:Key:geological
+    hazmat: DE:Key:hazmat
+    highway: DE:Key:highway
+    historic: DE:Key:historic
+    incline: DE:Key:incline
+    landuse: DE:Key:landuse
+    lanes: DE:Key:lanes
+    layer: DE:Key:layer
+    leisure: DE:Key:leisure
+    lit: DE:Key:lit
+    man_made: DE:Key:man made
+    maxheight: DE:Key:maxheight
+    maxspeed: DE:Key:maxspeed
+    military: DE:Key:military
+    mtb:scale: DE:Key:mtb:scale
+    name: DE:Key:name
+    natural: DE:Key:natural
+    noexit: DE:Key:noexit
+    note: DE:Key:note
+    oneway: DE:Key:oneway
+    opening_hours: DE:Key:opening hours
+    operator: DE:Key:operator
+    osmc:symbol: DE:Key:osmc:symbol
+    place: DE:Key:place
+    power: DE:Key:power
+    power_rating: DE:Key:power rating
+    railway: DE:Key:railway
+    route: DE:Key:route
+    sac_scale: DE:Key:sac scale
+    service: DE:Key:service
+    shop: DE:Key:shop
+    smoothness: DE:Key:smoothness
+    sport: DE:Key:sport
+    step_count: DE:Key:step count
+    surface: DE:Key:surface
+    tourism: DE:Key:tourism
+    tracktype: DE:Key:tracktype
+    trail_visibility: DE:Key:trail visibility
+    tunnel: DE:Key:tunnel
+    voltage: DE:Key:voltage
+    waterway: DE:Key:waterway
+    wheelchair: DE:Key:wheelchair
+    wires: DE:Key:wires
+    wood: DE:Key:wood
+en:
+  key:
+    Demolished: Key:Demolished
+    TMC:Direction: Key:TMC:Direction
+    TMC:LocationCode: Key:TMC:LocationCode
+    TMC:NextLocationCode: Key:TMC:NextLocationCode
+    TMC:PrevLocationCode: Key:TMC:PrevLocationCode
+    abutters: Key:abutters
+    access: Key:access
+    addr: Key:addr
+    addr:conscriptionnumber: Key:addr:conscriptionnumber
+    addr:provisionalnumber: Key:addr:provisionalnumber
+    addr:streetnumber: Key:addr:streetnumber
+    aerialway: Key:aerialway
+    aeroway: Key:aeroway
+    amenity: Key:amenity
+    area: Key:area
+    atv: Key:atv
+    barrier: Key:barrier
+    basin: Key:basin
+    bicycle: Key:bicycle
+    boat: Key:boat
+    border_type: Key:border type
+    boundary: Key:boundary
+    bridge: Key:bridge
+    building: Key:building
+    bunker_type: Key:bunker type
+    capacity: Key:capacity
+    cep: Key:cep
+    collection_times: Key:collection times
+    comment: Key:comment
+    construction: Key:construction
+    contact: Key:contact
+    covered: Key:covered
+    created_by: Key:created by
+    crossing: Key:crossing
+    cuisine: Key:cuisine
+    cutting: Key:cutting
+    cycleway: Key:cycleway
+    denomination: Key:denomination
+    description: Key:description
+    designation: Key:designation
+    direction: Key:direction
+    dispensing: Key:dispensing
+    disused: Key:disused
+    drink: Key:drink
+    easy_overtaking: Key:easy overtaking
+    ele: Key:ele
+    electrified: Key:electrified
+    embankment: Key:embankment
+    emergency: Key:emergency
+    end_date: Key:end date
+    enforcement: Key:enforcement
+    fee: Key:fee
+    fence_type: Key:fence type
+    fenced: Key:fenced
+    fixme: Key:fixme
+    foot: Key:foot
+    gauge: Key:gauge
+    geological: Key:geological
+    hazmat: Key:hazmat
+    healthcare: Key:healthcare
+    height: Key:height
+    highway: Key:highway
+    historic: Key:historic
+    horse: Key:horse
+    incline: Key:incline
+    information: Key:information
+    internet_access: Key:internet access
+    is_in: Key:is in
+    junction: Key:junction
+    landuse: Key:landuse
+    lanes: Key:lanes
+    layer: Key:layer
+    lcn_ref: Key:lcn ref
+    leisure: Key:leisure
+    lit: Key:lit
+    lit:perceived: Key:lit:perceived
+    lock: Key:lock
+    man_made: Key:man made
+    manhole: Key:manhole
+    maxairdraft: Key:maxairdraft
+    maxaxleload: Key:maxaxleload
+    maxdraught: Key:maxdraught
+    maxheight: Key:maxheight
+    maxheight:legal: Key:maxheight:legal
+    maxheight:marine: Key:maxheight:marine
+    maxheight:physical: Key:maxheight:physical
+    maxlength: Key:maxlength
+    maxspeed: Key:maxspeed
+    maxstay: Key:maxstay
+    maxweight: Key:maxweight
+    maxwidth: Key:maxwidth
+    military: Key:military
+    minspeed: Key:minspeed
+    mooring: Key:mooring
+    motorcar: Key:motorcar
+    motorcycle: Key:motorcycle
+    motorroad: Key:motorroad
+    mountain_pass: Key:mountain pass
+    mtb:description: Key:mtb:description
+    mtb:scale: Key:mtb:scale
+    name: Key:name
+    name:cy: Key:name:cy
+    narrow: Key:narrow
+    natural: Key:natural
+    ncn_ref: Key:ncn ref
+    noexit: Key:noexit
+    noname: Key:noname
+    note: Key:note
+    oneway: Key:oneway
+    opening_hours: Key:opening hours
+    operator: Key:operator
+    osmarender:nameDirection: Key:osmarender:nameDirection
+    osmarender:render: Key:osmarender:render
+    osmarender:renderName: Key:osmarender:renderName
+    osmarender:renderRef: Key:osmarender:renderRef
+    osmc:symbol: Key:osmc:symbol
+    overtaking: Key:overtaking
+    parking: Key:parking
+    passing_places: Key:passing places
+    paved:date: Key:paved:date
+    phone: Key:phone
+    place: Key:place
+    population: Key:population
+    postal_code: Key:postal code
+    power: Key:power
+    power_rating: Key:power rating
+    power_source: Key:power source
+    proposed: Key:proposed
+    psv: Key:psv
+    railway: Key:railway
+    ramp: Key:ramp
+    rcn_ref: Key:rcn ref
+    ref: Key:ref
+    ref:isil: Key:ref:isil
+    religion: Key:religion
+    resource: Key:resource
+    route: Key:route
+    sac_scale: Key:sac scale
+    sagns_id: Key:sagns id
+    seamark: Key:seamark
+    seasonal:snowfall:regaintime: Key:seasonal:snowfall:regaintime
+    service: Key:service
+    shop: Key:shop
+    ski: Key:ski
+    smoothness: Key:smoothness
+    snowplowing: Key:snowplowing
+    snowplowing:category: Key:snowplowing:category
+    source: Key:source
+    sport: Key:sport
+    start_date: Key:start date
+    step_count: Key:step count
+    stop: Key:stop
+    sulky: Key:sulky
+    surface: Key:surface
+    tactile_paving: Key:tactile paving
+    toll: Key:toll
+    tourism: Key:tourism
+    tracktype: Key:tracktype
+    traffic:hourly: Key:traffic:hourly
+    traffic_calming: Key:traffic calming
+    traffic_sign: Key:traffic sign
+    trail_visibility: Key:trail visibility
+    trolley_wire: Key:trolley wire
+    tunnel: Key:tunnel
+    type: Key:type
+    voltage: Key:voltage
+    waterway: Key:waterway
+    website: Key:website
+    wheelchair: Key:wheelchair
+    width: Key:width
+    wikipedia: Key:wikipedia
+    wires: Key:wires
+    woeid: Key:woeid
+    wood: Key:wood
+    zoo: Key:zoo
+et:
+  key:
+    highway: Et:Key:highway
+fi:
+  key:
+    amenity: Fi:Key:amenity
+    bridge: Fi:Key:bridge
+    crossing: Fi:Key:crossing
+    description: Fi:Key:description
+    disused: Fi:Key:disused
+    ele: Fi:Key:ele
+    embankment: Fi:Key:embankment
+    hazmat: Fi:Key:hazmat
+    lanes: Fi:Key:lanes
+    layer: Fi:Key:layer
+    leisure: Fi:Key:leisure
+    man_made: Fi:Key:man made
+    manhole: Fi:Key:manhole
+    narrow: Fi:Key:narrow
+    natural: Fi:Key:natural
+    note: Fi:Key:note
+    operator: Fi:Key:operator
+    shop: Fi:Key:shop
+    surface: Fi:Key:surface
+    tracktype: Fi:Key:tracktype
+    traffic_calming: Fi:Key:traffic calming
+    tunnel: Fi:Key:tunnel
+    waterway: Fi:Key:waterway
+    wheelchair: Fi:Key:wheelchair
+    width: Fi:Key:width
+fr:
+  key:
+    addr: FR:Key:addr
+    amenity: FR:Key:amenity
+    barrier: FR:Key:barrier
+    boundary: FR:Key:boundary
+    bridge: FR:Key:bridge
+    building: FR:Key:building
+    collection_times: FR:Key:collection times
+    cycleway: FR:Key:cycleway
+    enforcement: FR:Key:enforcement
+    highway: FR:Key:highway
+    landuse: FR:Key:landuse
+    lanes: FR:Key:lanes
+    maxweight: FR:Key:maxweight
+    name: FR:Key:name
+    noname: FR:Key:noname
+    opening_hours: FR:Key:opening hours
+    power: FR:Key:power
+    sac_scale: FR:Key:sac scale
+    shop: FR:Key:shop
+    smoothness: FR:Key:smoothness
+    waterway: FR:Key:waterway
+hr:
+  key:
+    tracktype: Hr:Key:tracktype
+hu:
+  key:
+    aeroway: HU:Key:aeroway
+    shop: HU:Key:shop
+    tourism: HU:Key:tourism
+it:
+  key:
+    aerialway: IT:Key:aerialway
+    aeroway: IT:Key:aeroway
+    amenity: IT:Key:amenity
+    barrier: IT:Key:barrier
+    boundary: IT:Key:boundary
+    bridge: IT:Key:bridge
+    building: IT:Key:building
+    construction: IT:Key:construction
+    cutting: IT:Key:cutting
+    cycleway: IT:Key:cycleway
+    denomination: IT:Key:denomination
+    embankment: IT:Key:embankment
+    enforcement: IT:Key:enforcement
+    geological: IT:Key:geological
+    highway: IT:Key:highway
+    historic: IT:Key:historic
+    junction: IT:Key:junction
+    landuse: IT:Key:landuse
+    leisure: IT:Key:leisure
+    lock: IT:Key:lock
+    man_made: IT:Key:man made
+    military: IT:Key:military
+    mooring: IT:Key:mooring
+    name: IT:Key:name
+    natural: IT:Key:natural
+    osmc:symbol: IT:Key:osmc:symbol
+    passing_places: IT:Key:passing places
+    place: IT:Key:place
+    power: IT:Key:power
+    proposed: IT:Key:proposed
+    railway: IT:Key:railway
+    ref: IT:Key:ref
+    religion: IT:Key:religion
+    route: IT:Key:route
+    sac_scale: IT:Key:sac scale
+    service: IT:Key:service
+    shop: IT:Key:shop
+    sport: IT:Key:sport
+    stop: IT:Key:stop
+    tourism: IT:Key:tourism
+    tracktype: IT:Key:tracktype
+    traffic_calming: IT:Key:traffic calming
+    trail_visibility: IT:Key:trail visibility
+    tunnel: IT:Key:tunnel
+    type: IT:Key:type
+    waterway: IT:Key:waterway
+    wheelchair: IT:Key:wheelchair
+ja:
+  key:
+    abutters: Ja:Key:abutters
+    access: Ja:Key:access
+    aerialway: Ja:Key:aerialway
+    aeroway: Ja:Key:aeroway
+    amenity: Ja:Key:amenity
+    barrier: Ja:Key:barrier
+    boundary: Ja:Key:boundary
+    bridge: Ja:Key:bridge
+    building: Ja:Key:building
+    crossing: Ja:Key:crossing
+    cuisine: Ja:Key:cuisine
+    cycleway: Ja:Key:cycleway
+    fixme: Ja:Key:fixme
+    foot: Ja:Key:foot
+    highway: Ja:Key:highway
+    historic: Ja:Key:historic
+    incline: Ja:Key:incline
+    information: Ja:Key:information
+    internet_access: Ja:Key:internet access
+    landuse: Ja:Key:landuse
+    leisure: Ja:Key:leisure
+    man_made: Ja:Key:man made
+    military: Ja:Key:military
+    name: Ja:Key:name
+    natural: Ja:Key:natural
+    operator: Ja:Key:operator
+    phone: Ja:Key:phone
+    power: Ja:Key:power
+    railway: Ja:Key:railway
+    ref: Ja:Key:ref
+    route: Ja:Key:route
+    shop: Ja:Key:shop
+    step_count: Ja:Key:step count
+    surface: Ja:Key:surface
+    tactile_paving: Ja:Key:tactile paving
+    tourism: Ja:Key:tourism
+    tracktype: Ja:Key:tracktype
+    waterway: Ja:Key:waterway
+    wheelchair: Ja:Key:wheelchair
+    wood: Ja:Key:wood
+nl:
+  key:
+    cycleway: NL:Key:cycleway
+no:
+  key:
+    fenced: No:Key:fenced
+    maxheight:marine: No:Key:maxheight:marine
+pl:
+  key:
+    height: Pl:Key:height
+    oneway: Pl:Key:oneway
+pt-br:
+  key:
+    access: Pt-br:Key:access
+    addr: Pt-br:Key:addr
+    aeroway: Pt-br:Key:aeroway
+    amenity: Pt-br:Key:amenity
+    barrier: Pt-br:Key:barrier
+    bicycle: Pt-br:Key:bicycle
+    boat: Pt-br:Key:boat
+    border_type: Pt-br:Key:border type
+    boundary: Pt-br:Key:boundary
+    bridge: Pt-br:Key:bridge
+    building: Pt-br:Key:building
+    cep: Pt-br:Key:cep
+    construction: Pt-br:Key:construction
+    ele: Pt-br:Key:ele
+    emergency: Pt-br:Key:emergency
+    fenced: Pt-br:Key:fenced
+    foot: Pt-br:Key:foot
+    hgv: Pt-br:Key:hgv
+    highway: Pt-br:Key:highway
+    horse: Pt-br:Key:horse
+    landuse: Pt-br:Key:landuse
+    lanes: Pt-br:Key:lanes
+    leisure: Pt-br:Key:leisure
+    man_made: Pt-br:Key:man made
+    maxdraught: Pt-br:Key:maxdraught
+    maxheight: Pt-br:Key:maxheight
+    maxheight:legal: Pt-br:Key:maxheight:legal
+    maxheight:marine: Pt-br:Key:maxheight:marine
+    maxheight:physical: Pt-br:Key:maxheight:physical
+    maxspeed: Pt-br:Key:maxspeed
+    maxweight: Pt-br:Key:maxweight
+    military: Pt-br:Key:military
+    motorcar: Pt-br:Key:motorcar
+    motorcycle: Pt-br:Key:motorcycle
+    name: Pt-br:Key:name
+    natural: Pt-br:Key:natural
+    noname: Pt-br:Key:noname
+    oneway: Pt-br:Key:oneway
+    operator: Pt-br:Key:operator
+    psv: Pt-br:Key:psv
+    religion: Pt-br:Key:religion
+    seamark: Pt-br:Key:seamark
+    shop: Pt-br:Key:shop
+    ski: Pt-br:Key:ski
+    source: Pt-br:Key:source
+    sport: Pt-br:Key:sport
+    surface: Pt-br:Key:surface
+    type: Pt-br:Key:type
+    waterway: Pt-br:Key:waterway
+ru:
+  key:
+    abutters: RU:Key:abutters
+    access: RU:Key:access
+    addr: RU:Key:addr
+    aerialway: RU:Key:aerialway
+    aeroway: RU:Key:aeroway
+    amenity: RU:Key:amenity
+    area: RU:Key:area
+    bicycle: RU:Key:bicycle
+    boat: RU:Key:boat
+    border_type: RU:Key:border type
+    boundary: RU:Key:boundary
+    building: RU:Key:building
+    bunker_type: RU:Key:bunker type
+    capacity: RU:Key:capacity
+    comment: RU:Key:comment
+    construction: RU:Key:construction
+    created_by: RU:Key:created by
+    crossing: RU:Key:crossing
+    cuisine: RU:Key:cuisine
+    cutting: RU:Key:cutting
+    denomination: RU:Key:denomination
+    description: RU:Key:description
+    direction: RU:Key:direction
+    disused: RU:Key:disused
+    ele: RU:Key:ele
+    embankment: RU:Key:embankment
+    fee: RU:Key:fee
+    fixme: RU:Key:fixme
+    foot: RU:Key:foot
+    gauge: RU:Key:gauge
+    height: RU:Key:height
+    highway: RU:Key:highway
+    historic: RU:Key:historic
+    horse: RU:Key:horse
+    information: RU:Key:information
+    internet_access: RU:Key:internet access
+    junction: RU:Key:junction
+    landuse: RU:Key:landuse
+    lanes: RU:Key:lanes
+    leisure: RU:Key:leisure
+    man_made: RU:Key:man made
+    maxheight: RU:Key:maxheight
+    maxlength: RU:Key:maxlength
+    maxspeed: RU:Key:maxspeed
+    maxweight: RU:Key:maxweight
+    maxwidth: RU:Key:maxwidth
+    military: RU:Key:military
+    minspeed: RU:Key:minspeed
+    name: RU:Key:name
+    natural: RU:Key:natural
+    noexit: RU:Key:noexit
+    note: RU:Key:note
+    oneway: RU:Key:oneway
+    opening_hours: RU:Key:opening hours
+    operator: RU:Key:operator
+    parking: RU:Key:parking
+    passing_places: RU:Key:passing places
+    paved:date: RU:Key:paved:date
+    phone: RU:Key:phone
+    place: RU:Key:place
+    population: RU:Key:population
+    power: RU:Key:power
+    railway: RU:Key:railway
+    ref: RU:Key:ref
+    religion: RU:Key:religion
+    route: RU:Key:route
+    service: RU:Key:service
+    shop: RU:Key:shop
+    smoothness: RU:Key:smoothness
+    source: RU:Key:source
+    surface: RU:Key:surface
+    tourism: RU:Key:tourism
+    tracktype: RU:Key:tracktype
+    traffic_calming: RU:Key:traffic calming
+    type: RU:Key:type
+    waterway: RU:Key:waterway
+    website: RU:Key:website
+    width: RU:Key:width
+    wikipedia: RU:Key:wikipedia
+    wood: RU:Key:wood
+tr:
+  key:
+    amenity: Tr:Key:amenity
+    boundary: Tr:Key:boundary
+    highway: Tr:Key:highway
+    historic: Tr:Key:historic
+    leisure: Tr:Key:leisure
+    shop: Tr:Key:shop
+    sport: Tr:Key:sport
+uk:
+  key:
+    access: Uk:Key:access
+    highway: Uk:Key:highway
+    place: Uk:Key:place
+zh-hans:
+  key:
+    place: Zh-hans:Key:place
+
diff --git a/script/misc/update-key-and-tag-description-pages-from-wiki b/script/misc/update-key-and-tag-description-pages-from-wiki
new file mode 100644 (file)
index 0000000..c6550f6
--- /dev/null
@@ -0,0 +1,149 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use Pod::Usage ();
+use Getopt::Long ();
+
+BEGIN {
+    eval "require MediaWiki::API; require YAML::XS;" or do {
+        print "You have to install some modules via CPAN to run this:\n";
+        print "   sudo cpanp MediaWiki::API YAML::XS\n";
+        exit 1;
+    };
+}
+
+use MediaWiki::API;
+use YAML::XS qw(Dump);
+use Test::More 'no_plan';
+
+=head1 NAME
+
+update-key-and-tag-description-pages-from-wiki - Screen-scrape the wiki for key/value wiki description pages
+
+=head1 SYNOPSIS
+
+    perl script/misc/update-key-and-tag-description-pages-from-wiki config/wiki-tag-and-key-description.yml 
+
+=head1 BUGS
+
+This will break if there are more than 500 key or value pages. Paging
+needs to be implemenented.
+
+That or using a proper API or something (if it's there) or making a
+direct query to the wiki database.
+
+=cut
+
+# Get the command-line options
+Getopt::Long::Parser->new(
+    config => [ qw< bundling no_ignore_case no_require_order pass_through > ],
+)->getoptions(
+    'h|help' => \my $help,
+) or help();
+
+# On --help
+help() if $help;
+
+help() unless $ARGV[0];
+
+# Get a API interface
+my $mw = MediaWiki::API->new();
+ok($mw, "Got a MediaWiki API");
+$mw->{config}->{api_url} = 'http://wiki.openstreetmap.org/w/api.php';
+
+# All our goodies
+my (%feature, %count);
+
+# This is what you get on:
+## http://wiki.openstreetmap.org/w/index.php?search=Template:KeyDescription&fulltext=Search&fulltext=Search
+for my $lang ('', map { "${_}:" } qw[ Pt Fi De It HU Cz Fr RU Pl ]) {
+    ok(1, "  Templates for language '$lang'");
+
+    # Key/value pages
+    for my $thing (qw(key value)) {
+        my $Thing = ucfirst $thing;
+        ok(1, "    Getting $thing pages");
+        my $cnt = stick_content_in_hash($thing, "Template:${lang}${Thing}Description", \%feature);
+        ok(1, "    Got $cnt $thing pages");
+        $count{$thing} += $cnt;
+    }
+}
+
+ok(1, "Got a total of $count{$_} ${_}s") for qw[ key value ];
+
+# Dump to .yml file
+open my $out, ">", $ARGV[0] or die "Can't open file '$ARGV[0]' supplied on the command line";
+say $out "# THIS FILE IS AUTOGENERATED WITH THE script/misc/update-key-and-tag-description-pages-from-wiki";
+say $out "# PROGRAM DO NOT MANUALLY EDIT IT";
+say $out "";
+say $out Dump(\%feature);
+close $out;
+
+exit 0;
+
+sub stick_content_in_hash
+{
+    my ($key, $title, $hash) = @_;
+    my $ukey = ucfirst $key;
+
+    my $space_to_underscore = sub {
+        my $txt = shift;
+        $txt =~ s/ /_/g;
+        $txt;
+    };
+
+    my $count = 0;
+    get_embeddedin(
+        $title,
+        sub {
+            my ($links) = @_;
+            my (@links) = @$links;
+            ok(1, "    ... got " . scalar(@links) . " more links");
+            for my $link (@links) {
+                $count++;
+                my $title = $link->{title};
+
+                if ($title =~ /^$ukey:(?<key_name>.*?)$/) {
+                    # English by default
+                    $hash->{en}->{$key}->{ $space_to_underscore->($+{key_name}) } = $title;
+                } elsif ($title =~ /^(?<lang>[^:]+):$ukey:(?<key_name>.*?)$/) {
+                    $hash->{lc $+{lang}}->{$key}->{ $space_to_underscore->($+{key_name}) } = $title;
+                }
+            }
+        }
+    );
+
+    return $count;
+}
+
+sub get_embeddedin
+{
+    my ($title, $callback) = @_;
+    my $articles = $mw->list(
+        {
+            action => 'query',
+            list => 'embeddedin',
+            eititle => $title,
+            eifilterredir => 'nonredirects',
+            # Doesn't work for De:* and anything non-en. Odd.
+            # einamespace => '0|8',
+            eilimit => '200',
+        },
+        {
+            max => '0',
+            hook => $callback,
+            skip_encoding => 1,
+        }
+    ) || die $mw->{error}->{code} . ': ' . $mw->{error}->{details};
+}
+
+sub help
+{
+    my %arg = @_;
+
+    Pod::Usage::pod2usage(
+        -verbose => $arg{ verbose },
+        -exitval => $arg{ exitval } || 0,
+    );
+}