]> git.openstreetmap.org Git - nominatim.git/blob - test/python/api/test_localization.py
Merge remote-tracking branch 'upstream/master'
[nominatim.git] / test / python / api / test_localization.py
1 # SPDX-License-Identifier: GPL-3.0-or-later
2 #
3 # This file is part of Nominatim. (https://nominatim.org)
4 #
5 # Copyright (C) 2025 by the Nominatim developer community.
6 # For a full list of authors see the git log.
7 """
8 Test functions for adapting results to the user's locale.
9 """
10 import pytest
11
12 from nominatim_api import Locales
13
14
15 def test_display_name_empty_names():
16     loc = Locales(['en', 'de'])
17
18     assert loc.display_name(None) == ''
19     assert loc.display_name({}) == ''
20
21
22 def test_display_name_none_localized():
23     loc = Locales()
24
25     assert loc.display_name({}) == ''
26     assert loc.display_name({'name:de': 'DE', 'name': 'ALL'}) == 'ALL'
27     assert loc.display_name({'ref': '34', 'name:de': 'DE'}) == '34'
28
29
30 def test_output_names_none_localized():
31     loc = Locales()
32
33     expected_tags = [
34         'name', '_place_name', 'brand', '_place_brand', 'official_name', '_place_official_name',
35         'short_name', '_place_short_name', 'ref', '_place_ref'
36     ]
37
38     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
39
40
41 def test_output_names_none_localized_and_custom_output_names(monkeypatch):
42     monkeypatch.setenv(
43         'NOMINATIM_OUTPUT_NAMES',
44         'name:XX,entrance:XX,name,brand,test_tag,'
45         'official_name:XX,short_name:XX,alt_name:XX'
46     )
47     loc = Locales()
48
49     expected_tags = [
50         'name', '_place_name', 'brand', '_place_brand', 'test_tag', '_place_test_tag'
51     ]
52
53     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
54
55
56 def test_output_names_none_localized_and_custom_output_names_more_than_two_changes(monkeypatch):
57     monkeypatch.setenv(
58         'NOMINATIM_OUTPUT_NAMES',
59         'name:XX,brand,test_tag:XX,official_name,short_name:XX,'
60         'alt_name,another_tag_with:XX,another_tag_withoutXX'
61     )
62     loc = Locales()
63
64     expected_tags = [
65         'brand', '_place_brand', 'official_name', '_place_official_name', 'alt_name',
66         '_place_alt_name', 'another_tag_withoutXX', '_place_another_tag_withoutXX'
67     ]
68
69     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
70
71
72 def test_output_names_none_localized_and_custom_output_names_including_space(monkeypatch):
73     monkeypatch.setenv(
74         'NOMINATIM_OUTPUT_NAMES',
75         'name:XX,name ,short_name:XX, short_name'
76     )
77     loc = Locales()
78
79     expected_tags = [
80         'name', '_place_name', 'short_name', '_place_short_name'
81     ]
82
83     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
84
85
86 def test_display_name_localized():
87     loc = Locales(['en', 'de'])
88
89     assert loc.display_name({}) == ''
90     assert loc.display_name({'name:de': 'DE', 'name': 'ALL'}) == 'DE'
91     assert loc.display_name({'ref': '34', 'name:de': 'DE'}) == 'DE'
92
93
94 def test_output_names_localized():
95     loc = Locales(['en', 'es'])
96
97     expected_tags = [
98         'name:en', '_place_name:en', 'name:es', '_place_name:es', 'name', '_place_name', 'brand',
99         '_place_brand', 'official_name:en', '_place_official_name:en', 'official_name:es',
100         '_place_official_name:es', 'short_name:en', '_place_short_name:en', 'short_name:es',
101         '_place_short_name:es', 'official_name', '_place_official_name', 'short_name',
102         '_place_short_name', 'ref', '_place_ref'
103     ]
104
105     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
106
107
108 def test_output_names_localized_and_custom_output_names_including_space(monkeypatch):
109     monkeypatch.setenv(
110         'NOMINATIM_OUTPUT_NAMES',
111         'name:XX,name ,short_name:XX, short_name'
112     )
113     loc = Locales(['en', 'es'])
114
115     expected_tags = [
116         'name:en', '_place_name:en', 'name:es', '_place_name:es',
117         'name', '_place_name',
118         'short_name:en', '_place_short_name:en', 'short_name:es', '_place_short_name:es',
119         'short_name', '_place_short_name'
120     ]
121
122     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
123
124
125 def test_output_names_localized_and_custom_output_names(monkeypatch):
126     monkeypatch.setenv(
127         'NOMINATIM_OUTPUT_NAMES',
128         'name:XX,entrance:XX,name,brand,test_tag,official_name:XX,short_name:XX,alt_name:XX'
129     )
130     loc = Locales(['en', 'es'])
131
132     expected_tags = [
133         'name:en', '_place_name:en', 'name:es', '_place_name:es', 'entrance:en',
134         '_place_entrance:en', 'entrance:es', '_place_entrance:es', 'name', '_place_name',
135         'brand', '_place_brand', 'test_tag', '_place_test_tag', 'official_name:en',
136         '_place_official_name:en', 'official_name:es', '_place_official_name:es',
137         'short_name:en', '_place_short_name:en', 'short_name:es', '_place_short_name:es',
138         'alt_name:en', '_place_alt_name:en', 'alt_name:es', '_place_alt_name:es'
139     ]
140
141     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
142
143
144 def test_output_names_localized_and_custom_output_names_start_with_tag_that_has_no_XX(monkeypatch):
145     monkeypatch.setenv(
146         'NOMINATIM_OUTPUT_NAMES',
147         'name,brand,test_tag,official_name:XX,short_name:XX,alt_name:XX'
148     )
149     loc = Locales(['en', 'es'])
150
151     expected_tags = [
152         'name', '_place_name', 'brand', '_place_brand', 'test_tag', '_place_test_tag',
153         'official_name:en', '_place_official_name:en', 'official_name:es',
154         '_place_official_name:es', 'short_name:en', '_place_short_name:en', 'short_name:es',
155         '_place_short_name:es', 'alt_name:en', '_place_alt_name:en', 'alt_name:es',
156         '_place_alt_name:es'
157     ]
158
159     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
160
161
162 def test_output_names_localized_and_custom_output_names_no_named_tags(monkeypatch):
163     monkeypatch.setenv(
164         'NOMINATIM_OUTPUT_NAMES',
165         'name,brand,test_tag'
166     )
167     loc = Locales(['en', 'es'])
168
169     expected_tags = [
170         'name', '_place_name', 'brand', '_place_brand', 'test_tag', '_place_test_tag'
171     ]
172
173     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
174
175
176 def test_output_names_localized_and_custom_output_names_only_named_tags(monkeypatch):
177     monkeypatch.setenv(
178         'NOMINATIM_OUTPUT_NAMES',
179         'name:XX,entrance:XX,official_name:XX,short_name:XX,alt_name:XX'
180     )
181     loc = Locales(['en', 'es'])
182
183     expected_tags = [
184         'name:en', '_place_name:en', 'name:es', '_place_name:es', 'entrance:en',
185         '_place_entrance:en', 'entrance:es', '_place_entrance:es', 'official_name:en',
186         '_place_official_name:en', 'official_name:es', '_place_official_name:es',
187         'short_name:en', '_place_short_name:en', 'short_name:es', '_place_short_name:es',
188         'alt_name:en', '_place_alt_name:en', 'alt_name:es', '_place_alt_name:es'
189     ]
190
191     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
192
193
194 def test_output_names_localized_and_custom_output_names_more_than_two_changes(monkeypatch):
195     monkeypatch.setenv(
196         'NOMINATIM_OUTPUT_NAMES',
197         'name:XX,brand,test_tag:XX,official_name,short_name:XX,'
198         'alt_name,another_tag_with:XX,another_tag_withoutXX'
199     )
200     loc = Locales(['en', 'es'])
201
202     expected_tags = [
203         'name:en', '_place_name:en', 'name:es', '_place_name:es', 'brand', '_place_brand',
204         'test_tag:en', '_place_test_tag:en', 'test_tag:es', '_place_test_tag:es', 'official_name',
205         '_place_official_name', 'short_name:en', '_place_short_name:en', 'short_name:es',
206         '_place_short_name:es', 'alt_name', '_place_alt_name', 'another_tag_with:en',
207         '_place_another_tag_with:en', 'another_tag_with:es', '_place_another_tag_with:es',
208         'another_tag_withoutXX', '_place_another_tag_withoutXX'
209     ]
210
211     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
212
213
214 def test_output_names_localized_and_custom_output_names_XX_in_the_middle(monkeypatch):
215     monkeypatch.setenv(
216         'NOMINATIM_OUTPUT_NAMES',
217         'name:XX,br:XXand,test_tag:XX,official_name,sh:XXort_name:XX,'
218         'alt_name,another_tag_with:XX,another_tag_withoutXX'
219     )
220     loc = Locales(['en', 'es'])
221
222     expected_tags = [
223         'name:en', '_place_name:en', 'name:es', '_place_name:es', 'br:XXand', '_place_br:XXand',
224         'test_tag:en', '_place_test_tag:en', 'test_tag:es', '_place_test_tag:es', 'official_name',
225         '_place_official_name', 'sh:XXort_name:en', '_place_sh:XXort_name:en', 'sh:XXort_name:es',
226         '_place_sh:XXort_name:es', 'alt_name', '_place_alt_name', 'another_tag_with:en',
227         '_place_another_tag_with:en', 'another_tag_with:es', '_place_another_tag_with:es',
228         'another_tag_withoutXX', '_place_another_tag_withoutXX'
229     ]
230
231     assert loc.name_tags == expected_tags, f'Expected {expected_tags}, but got {loc.name_tags}'
232
233
234 def test_display_name_preference():
235     loc = Locales(['en', 'de'])
236
237     assert loc.display_name({}) == ''
238     assert loc.display_name({'name:de': 'DE', 'name:en': 'EN'}) == 'EN'
239     assert loc.display_name({'official_name:en': 'EN', 'name:de': 'DE'}) == 'DE'
240
241
242 @pytest.mark.parametrize('langstr,langlist',
243                          [('fr', ['fr']),
244                           ('fr-FR', ['fr-FR', 'fr']),
245                           ('de,fr-FR', ['de', 'fr-FR', 'fr']),
246                           ('fr,de,fr-FR', ['fr', 'de', 'fr-FR']),
247                           ('en;q=0.5,fr', ['fr', 'en']),
248                           ('en;q=0.5,fr,en-US', ['fr', 'en-US', 'en']),
249                           ('en,fr;garbage,de', ['en', 'de'])])
250 def test_from_language_preferences(langstr, langlist):
251     assert Locales.from_accept_languages(langstr).languages == langlist