Replace hardcoded strings using translation json file

This introduces a new "translations.json" file under app/static/settings
that is loaded on app init and uses the user config value for interface
language to determine the appropriate strings to use in Whoogle-specific
elements of the UI (primarily only on the home page).
This commit is contained in:
Ben Busby 2021-05-24 13:28:55 -04:00
parent 7c221b7f7f
commit ef6bb5fec0
No known key found for this signature in database
GPG Key ID: 3B08611DF6E62ED2
8 changed files with 78 additions and 29 deletions

View File

@ -33,6 +33,8 @@ app.config['LANGUAGES'] = json.load(open(
os.path.join(app.config['STATIC_FOLDER'], 'settings/languages.json'))) os.path.join(app.config['STATIC_FOLDER'], 'settings/languages.json')))
app.config['COUNTRIES'] = json.load(open( app.config['COUNTRIES'] = json.load(open(
os.path.join(app.config['STATIC_FOLDER'], 'settings/countries.json'))) os.path.join(app.config['STATIC_FOLDER'], 'settings/countries.json')))
app.config['TRANSLATIONS'] = json.load(open(
os.path.join(app.config['STATIC_FOLDER'], 'settings/translations.json')))
app.config['CONFIG_PATH'] = os.getenv( app.config['CONFIG_PATH'] = os.getenv(
'CONFIG_VOLUME', 'CONFIG_VOLUME',
os.path.join(app.config['STATIC_FOLDER'], 'config')) os.path.join(app.config['STATIC_FOLDER'], 'config'))

View File

@ -77,6 +77,18 @@ class Config:
return key in self.safe_keys return key in self.safe_keys
def get_interface_lang(self):
"""Returns the correct language to use for localization, but falls
back to english if not set.
Returns:
str -- the interface language string
"""
if self.lang_interface:
return self.lang_interface
return 'lang_en'
def from_params(self, params) -> 'Config': def from_params(self, params) -> 'Config':
"""Modify user config with search parameters. This is primarily """Modify user config with search parameters. This is primarily
used for specifying configuration on a search-by-search basis on used for specifying configuration on a search-by-search basis on

View File

@ -130,6 +130,9 @@ def index():
return render_template('index.html', return render_template('index.html',
languages=app.config['LANGUAGES'], languages=app.config['LANGUAGES'],
countries=app.config['COUNTRIES'], countries=app.config['COUNTRIES'],
translation=app.config['TRANSLATIONS'][
g.user_config.get_interface_lang()
],
logo=render_template( logo=render_template(
'logo.html', 'logo.html',
dark=g.user_config.dark), dark=g.user_config.dark),
@ -235,6 +238,9 @@ def search():
query=urlparse.unquote(query), query=urlparse.unquote(query),
search_type=search_util.search_type, search_type=search_util.search_type,
config=g.user_config, config=g.user_config,
translation=app.config['TRANSLATIONS'][
g.user_config.get_interface_lang()
],
response=response, response=response,
version_number=app.config['VERSION_NUMBER'], version_number=app.config['VERSION_NUMBER'],
search_header=(render_template( search_header=(render_template(

View File

@ -1,5 +1,5 @@
[ [
{"name": "Default (none)", "value": ""}, {"name": "-------", "value": ""},
{"name": "Afghanistan", "value": "countryAF"}, {"name": "Afghanistan", "value": "countryAF"},
{"name": "Albania", "value": "countryAL"}, {"name": "Albania", "value": "countryAL"},
{"name": "Algeria", "value": "countryDZ"}, {"name": "Algeria", "value": "countryDZ"},

View File

@ -1,5 +1,5 @@
[ [
{"name": "Default (none specified)", "value": ""}, {"name": "-------", "value": ""},
{"name": "English", "value": "lang_en"}, {"name": "English", "value": "lang_en"},
{"name": "Afrikaans", "value": "lang_af"}, {"name": "Afrikaans", "value": "lang_af"},
{"name": "Arabic", "value": "lang_ar"}, {"name": "Arabic", "value": "lang_ar"},

View File

@ -0,0 +1,31 @@
{
"lang_en": {
"default-none": "Default (none specified)",
"search": "Search",
"config": "Configuration",
"config-country": "Filter Results by Country",
"config-country-help": "Note: If enabled, a website will only appear in the search results if it is *hosted* in the selected country.",
"config-lang": "Interface Language",
"config-lang-search": "Search Language",
"config-near": "Near",
"config-near-help": "City Name",
"config-block": "Block",
"config-block-help": "Comma-separated site list",
"config-nojs": "Show NoJS Links",
"config-dark": "Dark Mode",
"config-safe": "Safe Search",
"config-alts": "Replace Social Media Links",
"config-alts-help": "Replaces Twitter/YouTube/Instagram/etc links with privacy respecting alternatives.",
"config-new-tab": "Open Links in New Tab",
"config-images": "Full Size Image Search",
"config-images-help": "(Experimental) Adds the 'View Image' option to desktop image searches. This will cause image result thumbnails to be lower resolution.",
"config-tor": "Use Tor",
"config-get-only": "GET Requests Only",
"config-url": "Root URL",
"config-css": "Custom CSS",
"load": "Load",
"apply": "Apply",
"save-as": "Save As...",
"github-link": "View on GitHub"
}
}

View File

@ -20,7 +20,7 @@
<footer> <footer>
<p style="color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};"> <p style="color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};">
Whoogle Search v{{ version_number }} || Whoogle Search v{{ version_number }} ||
<a id="gh-link" href="https://github.com/benbusby/whoogle-search">View on GitHub</a> <a id="gh-link" href="https://github.com/benbusby/whoogle-search">{{ translation['github-link'] }}</a>
</p> </p>
</footer> </footer>
<script src="static/js/autocomplete.js"></script> <script src="static/js/autocomplete.js"></script>

View File

@ -53,17 +53,17 @@
autocorrect="off" autocorrect="off"
autocomplete="off"> autocomplete="off">
</div> </div>
<input type="submit" id="search-submit" value="Search"> <input type="submit" id="search-submit" value="{{ translation['search'] }}">
</div> </div>
</form> </form>
{% if not config_disabled %} {% if not config_disabled %}
<br/> <br/>
<button id="config-collapsible" class="collapsible">Configuration</button> <button id="config-collapsible" class="collapsible">{{ translation['config'] }}</button>
<div class="content"> <div class="content">
<div class="config-fields"> <div class="config-fields">
<form id="config-form" action="config" method="post"> <form id="config-form" action="config" method="post">
<div class="config-div config-div-ctry"> <div class="config-div config-div-ctry">
<label for="config-ctry">Filter Results by Country: </label> <label for="config-ctry">{{ translation['config-country'] }}: </label>
<select name="ctry" id="config-ctry"> <select name="ctry" id="config-ctry">
{% for ctry in countries %} {% for ctry in countries %}
<option value="{{ ctry.value }}" <option value="{{ ctry.value }}"
@ -74,10 +74,10 @@
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
<div><span class="info-text">Note: If enabled, a website will only appear in the results if it is *hosted* in the selected country.</span></div> <div><span class="info-text">{{ translation['config-country-help'] }}</span></div>
</div> </div>
<div class="config-div config-div-lang"> <div class="config-div config-div-lang">
<label for="config-lang-interface">Interface Language: </label> <label for="config-lang-interface">{{ translation['config-lang'] }}: </label>
<select name="lang_interface" id="config-lang-interface"> <select name="lang_interface" id="config-lang-interface">
{% for lang in languages %} {% for lang in languages %}
<option value="{{ lang.value }}" <option value="{{ lang.value }}"
@ -90,7 +90,7 @@
</select> </select>
</div> </div>
<div class="config-div config-div-search-lang"> <div class="config-div config-div-search-lang">
<label for="config-lang-search">Search Language: </label> <label for="config-lang-search">{{ translation['config-lang-search'] }}: </label>
<select name="lang_search" id="config-lang-search"> <select name="lang_search" id="config-lang-search">
{% for lang in languages %} {% for lang in languages %}
<option value="{{ lang.value }}" <option value="{{ lang.value }}"
@ -103,55 +103,53 @@
</select> </select>
</div> </div>
<div class="config-div config-div-near"> <div class="config-div config-div-near">
<label for="config-near">Near: </label> <label for="config-near">{{ translation['config-near'] }}: </label>
<input type="text" name="near" id="config-near" placeholder="City Name" value="{{ config.near }}"> <input type="text" name="near" id="config-near" placeholder="City Name" value="{{ config.near }}">
</div> </div>
<div class="config-div config-div-block"> <div class="config-div config-div-block">
<label for="config-block">Block: </label> <label for="config-block">{{ translation['config-block'] }}: </label>
<input type="text" name="block" id="config-block" placeholder="Comma-separated site list" value="{{ config.block }}"> <input type="text" name="block" id="config-block" placeholder="Comma-separated site list" value="{{ config.block }}">
</div> </div>
<div class="config-div config-div-nojs"> <div class="config-div config-div-nojs">
<label for="config-nojs">Show NoJS Links: </label> <label for="config-nojs">{{ translation['config-nojs'] }}: </label>
<input type="checkbox" name="nojs" id="config-nojs" {{ 'checked' if config.nojs else '' }}> <input type="checkbox" name="nojs" id="config-nojs" {{ 'checked' if config.nojs else '' }}>
</div> </div>
<div class="config-div config-div-dark"> <div class="config-div config-div-dark">
<label for="config-dark">Dark Mode: </label> <label for="config-dark">{{ translation['config-dark'] }}: </label>
<input type="checkbox" name="dark" id="config-dark" {{ 'checked' if config.dark else '' }}> <input type="checkbox" name="dark" id="config-dark" {{ 'checked' if config.dark else '' }}>
</div> </div>
<div class="config-div config-div-safe"> <div class="config-div config-div-safe">
<label for="config-safe">Safe Search: </label> <label for="config-safe">{{ translation['config-safe'] }}: </label>
<input type="checkbox" name="safe" id="config-safe" {{ 'checked' if config.safe else '' }}> <input type="checkbox" name="safe" id="config-safe" {{ 'checked' if config.safe else '' }}>
</div> </div>
<div class="config-div config-div-alts"> <div class="config-div config-div-alts">
<label class="tooltip" for="config-alts">Replace Social Media Links: </label> <label class="tooltip" for="config-alts">{{ translation['config-alts'] }}: </label>
<input type="checkbox" name="alts" id="config-alts" {{ 'checked' if config.alts else '' }}> <input type="checkbox" name="alts" id="config-alts" {{ 'checked' if config.alts else '' }}>
<div><span class="info-text"> — Replaces Twitter/YouTube/Instagram/Reddit links <div><span class="info-text"> — {{ translation['config-alts-help'] }}</span></div>
with Nitter/Invidious/Bibliogram/Libreddit links.</span></div>
</div> </div>
<div class="config-div config-div-new-tab"> <div class="config-div config-div-new-tab">
<label for="config-new-tab">Open Links in New Tab: </label> <label for="config-new-tab">{{ translation['config-new-tab'] }}: </label>
<input type="checkbox" name="new_tab" id="config-new-tab" {{ 'checked' if config.new_tab else '' }}> <input type="checkbox" name="new_tab" id="config-new-tab" {{ 'checked' if config.new_tab else '' }}>
</div> </div>
<div class="config-div config-div-view-image"> <div class="config-div config-div-view-image">
<label for="config-view-image">Full Size Image Search: </label> <label for="config-view-image">{{ translation['config-images'] }}: </label>
<input type="checkbox" name="view_image" id="config-view-image" {{ 'checked' if config.view_image else '' }}> <input type="checkbox" name="view_image" id="config-view-image" {{ 'checked' if config.view_image else '' }}>
<div><span class="info-text"> — (Experimental) Adds the "View Image" option on desktop to view full size images in search results. <div><span class="info-text"> — {{ translation['config-images-help'] }}</span></div>
This will cause image result thumbnails to be lower resolution.</span></div>
</div> </div>
<div class="config-div config-div-tor"> <div class="config-div config-div-tor">
<label for="config-tor">Use Tor: {{ '' if tor_available else 'Unavailable' }}</label> <label for="config-tor">{{ translation['config-tor'] }}: {{ '' if tor_available else 'Unavailable' }}</label>
<input type="checkbox" name="tor" id="config-tor" {{ '' if tor_available else 'hidden' }} {{ 'checked' if config.tor else '' }}> <input type="checkbox" name="tor" id="config-tor" {{ '' if tor_available else 'hidden' }} {{ 'checked' if config.tor else '' }}>
</div> </div>
<div class="config-div config-div-get-only"> <div class="config-div config-div-get-only">
<label for="config-get-only">GET Requests Only: </label> <label for="config-get-only">{{ translation['config-get-only'] }}: </label>
<input type="checkbox" name="get_only" id="config-get-only" {{ 'checked' if config.get_only else '' }}> <input type="checkbox" name="get_only" id="config-get-only" {{ 'checked' if config.get_only else '' }}>
</div> </div>
<div class="config-div config-div-root-url"> <div class="config-div config-div-root-url">
<label for="config-url">Root URL: </label> <label for="config-url">{{ translation['config-url'] }}: </label>
<input type="text" name="url" id="config-url" value="{{ config.url }}"> <input type="text" name="url" id="config-url" value="{{ config.url }}">
</div> </div>
<div class="config-div config-div-custom-css"> <div class="config-div config-div-custom-css">
<label for="config-style">Custom CSS:</label> <label for="config-style">{{ translation['config-css'] }}:</label>
<textarea <textarea
name="style" name="style"
id="config-style" id="config-style"
@ -164,9 +162,9 @@
</textarea> </textarea>
</div> </div>
<div class="config-div"> <div class="config-div">
<input type="submit" id="config-load" value="Load">&nbsp; <input type="submit" id="config-load" value="{{ translation['load'] }}">&nbsp;
<input type="submit" id="config-submit" value="Apply">&nbsp; <input type="submit" id="config-submit" value="{{ translation['apply'] }}">&nbsp;
<input type="submit" id="config-save" value="Save As..."> <input type="submit" id="config-save" value="{{ translation['save-as'] }}">
</div> </div>
</form> </form>
</div> </div>
@ -176,7 +174,7 @@
<footer> <footer>
<p style="color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};"> <p style="color: {{ 'var(--whoogle-dark-text)' if config.dark else 'var(--whoogle-text)' }};">
Whoogle Search v{{ version_number }} || Whoogle Search v{{ version_number }} ||
<a id="gh-link" href="https://github.com/benbusby/whoogle-search">View on GitHub</a> <a id="gh-link" href="https://github.com/benbusby/whoogle-search">{{ translation['github-link'] }}</a>
</p> </p>
</footer> </footer>
</body> </body>