Added Locales to the webextention
Build LinkLog Development Image / development-image (push) Successful in 9s
Build LinkLog Development Image / development-image (push) Successful in 9s
This commit is contained in:
@@ -14,7 +14,7 @@ XPI_FILE := LinkLog-$(EXTENSION_VERSION).xpi
|
|||||||
XPI_UNSIGNED_DIR := XPI/unsigned
|
XPI_UNSIGNED_DIR := XPI/unsigned
|
||||||
XPI_SIGNED_DIR := XPI/signed
|
XPI_SIGNED_DIR := XPI/signed
|
||||||
XPI_OUTPUT := $(XPI_UNSIGNED_DIR)/$(XPI_FILE)
|
XPI_OUTPUT := $(XPI_UNSIGNED_DIR)/$(XPI_FILE)
|
||||||
EXTENSION_FILES := manifest.json logo.svg icon-16.png icon-32.png icon-48.png icon-96.png options.css options.html options.js popup.css popup.html popup.js
|
EXTENSION_FILES := manifest.json logo.svg icon-16.png icon-32.png icon-48.png icon-96.png options.css options.html options.js popup.css popup.html popup.js l10n.js _locales/en-US/messages.json
|
||||||
EXTENSION_SOURCES := $(addprefix webextension/,$(EXTENSION_FILES))
|
EXTENSION_SOURCES := $(addprefix webextension/,$(EXTENSION_FILES))
|
||||||
XPI_VALIDATOR := scripts/release/validate_xpi.py
|
XPI_VALIDATOR := scripts/release/validate_xpi.py
|
||||||
|
|
||||||
|
|||||||
@@ -232,6 +232,14 @@ On the home page, when clicking on the avatar or the user, show the profile info
|
|||||||
### Assistant outcome
|
### Assistant outcome
|
||||||
Made each home-feed avatar and username link to the corresponding `/<username>/` profile page, added matching link layout styling, and added a regression assertion for the generated profile URL.
|
Made each home-feed avatar and username link to the corresponding `/<username>/` profile page, added matching link layout styling, and added a regression assertion for the generated profile URL.
|
||||||
|
|
||||||
|
## 2026-08-26
|
||||||
|
|
||||||
|
### User
|
||||||
|
Localize the firefox plugin.
|
||||||
|
|
||||||
|
### Assistant outcome
|
||||||
|
Added Firefox `browser.i18n` support with an `en-US` message catalog, localized popup and settings page labels and runtime messages, localized manifest metadata, and included the localization resources in XPI packaging and validation.
|
||||||
|
|
||||||
### User
|
### User
|
||||||
Show the avatar with each entry on the home page. On the specific /<user>/ page don't show the avatar and user name with each entry
|
Show the avatar with each entry on the home page. On the specific /<user>/ page don't show the avatar and user name with each entry
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,7 @@
|
|||||||
116. When the user is authorized and on its /<user>/ page show a Mastodon post button with logo; after posting keep it functional but change its color.
|
116. When the user is authorized and on its /<user>/ page show a Mastodon post button with logo; after posting keep it functional but change its color.
|
||||||
117. Continue to log interactions to the VIBE directory.
|
117. Continue to log interactions to the VIBE directory.
|
||||||
118. On the home page, when clicking on the avatar or the user, show the profile information.
|
118. On the home page, when clicking on the avatar or the user, show the profile information.
|
||||||
|
119. Localize the firefox plugin.
|
||||||
|
|
||||||
## Future entries
|
## Future entries
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -20,6 +20,8 @@ REQUIRED_FILES = {
|
|||||||
'popup.css',
|
'popup.css',
|
||||||
'popup.html',
|
'popup.html',
|
||||||
'popup.js',
|
'popup.js',
|
||||||
|
'l10n.js',
|
||||||
|
'_locales/en-US/messages.json',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
{
|
||||||
|
"extensionName": {
|
||||||
|
"message": "LinkLog"
|
||||||
|
},
|
||||||
|
"extensionDescription": {
|
||||||
|
"message": "Capture and submit page links to LinkLog."
|
||||||
|
},
|
||||||
|
"settingsTitle": {
|
||||||
|
"message": "LinkLog Settings"
|
||||||
|
},
|
||||||
|
"titleLabel": {
|
||||||
|
"message": "Title"
|
||||||
|
},
|
||||||
|
"urlLabel": {
|
||||||
|
"message": "URL"
|
||||||
|
},
|
||||||
|
"commentLabel": {
|
||||||
|
"message": "Comment"
|
||||||
|
},
|
||||||
|
"commentPlaceholder": {
|
||||||
|
"message": "Your comment"
|
||||||
|
},
|
||||||
|
"tagsLabel": {
|
||||||
|
"message": "Tags"
|
||||||
|
},
|
||||||
|
"loadingTags": {
|
||||||
|
"message": "Loading tags..."
|
||||||
|
},
|
||||||
|
"newTagsPlaceholder": {
|
||||||
|
"message": "#new-tag, #another-tag"
|
||||||
|
},
|
||||||
|
"saveLink": {
|
||||||
|
"message": "Save link"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"message": "Settings"
|
||||||
|
},
|
||||||
|
"signOut": {
|
||||||
|
"message": "Sign out"
|
||||||
|
},
|
||||||
|
"backendUrlLabel": {
|
||||||
|
"message": "Backend URL"
|
||||||
|
},
|
||||||
|
"usernameLabel": {
|
||||||
|
"message": "Username"
|
||||||
|
},
|
||||||
|
"usernamePlaceholder": {
|
||||||
|
"message": "alice"
|
||||||
|
},
|
||||||
|
"passwordLabel": {
|
||||||
|
"message": "Password"
|
||||||
|
},
|
||||||
|
"saveAndLogIn": {
|
||||||
|
"message": "Save and log in"
|
||||||
|
},
|
||||||
|
"thisPlugin": {
|
||||||
|
"message": "This Plugin"
|
||||||
|
},
|
||||||
|
"pluginDescription": {
|
||||||
|
"message": "This plugin will log links to a backend LinkLog server which will publish them on a website and potentially as an entry on a fediverse service or other locations, depending on the plugins configured."
|
||||||
|
},
|
||||||
|
"accountRequirement": {
|
||||||
|
"message": "Users of this plugin will need an account on a LinkLog server"
|
||||||
|
},
|
||||||
|
"privacy": {
|
||||||
|
"message": "Privacy"
|
||||||
|
},
|
||||||
|
"privacyDescription": {
|
||||||
|
"message": "This plugin respects your privacy and does not collect any personal data beyond what is necessary to log links to your LinkLog server."
|
||||||
|
},
|
||||||
|
"storedData": {
|
||||||
|
"message": "The URL - after a best effort try to remove tracking parameters -, the title of the webpage, a possible comment, and a timestamp of visit will be stored on the backend server, and will be made public in combination with the user's profile as registered on the backend server."
|
||||||
|
},
|
||||||
|
"backendHeading": {
|
||||||
|
"message": "LinkLog Backend"
|
||||||
|
},
|
||||||
|
"backendDescription": {
|
||||||
|
"message": "The backend URL is a selfhosted linklog application. See its"
|
||||||
|
},
|
||||||
|
"backendSource": {
|
||||||
|
"message": "for its source."
|
||||||
|
},
|
||||||
|
"copyright": {
|
||||||
|
"message": "Copyright © 2026 Olaf Kolkman"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"message": "Repository"
|
||||||
|
},
|
||||||
|
"signInToSelectTags": {
|
||||||
|
"message": "Sign in to select existing tags."
|
||||||
|
},
|
||||||
|
"loadTagsFailed": {
|
||||||
|
"message": "Could not load existing tags."
|
||||||
|
},
|
||||||
|
"submitting": {
|
||||||
|
"message": "Submitting..."
|
||||||
|
},
|
||||||
|
"configureAndLogIn": {
|
||||||
|
"message": "Please configure the backend URL and log in first."
|
||||||
|
},
|
||||||
|
"sessionExpired": {
|
||||||
|
"message": "Session expired. Re-authenticate in settings."
|
||||||
|
},
|
||||||
|
"submissionFailed": {
|
||||||
|
"message": "Submission failed"
|
||||||
|
},
|
||||||
|
"linkSaved": {
|
||||||
|
"message": "Link saved successfully"
|
||||||
|
},
|
||||||
|
"submissionFailedConnection": {
|
||||||
|
"message": "Submission failed. Check your backend connection."
|
||||||
|
},
|
||||||
|
"loggedInAt": {
|
||||||
|
"message": "$USERNAME$ logged in at $BACKEND$",
|
||||||
|
"placeholders": {
|
||||||
|
"username": {
|
||||||
|
"content": "$1"
|
||||||
|
},
|
||||||
|
"backend": {
|
||||||
|
"content": "$2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fillAllFields": {
|
||||||
|
"message": "Please fill in all fields"
|
||||||
|
},
|
||||||
|
"loginFailed": {
|
||||||
|
"message": "Login failed"
|
||||||
|
},
|
||||||
|
"loggedInSuccessfully": {
|
||||||
|
"message": "Logged in successfully"
|
||||||
|
},
|
||||||
|
"unableToLogIn": {
|
||||||
|
"message": "Unable to log in. Check backend URL and credentials."
|
||||||
|
},
|
||||||
|
"signedOut": {
|
||||||
|
"message": "Signed out"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright © 2026 Olaf Kolkman
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
function getLocalizedMessage(messageId, substitutions = []) {
|
||||||
|
const message = browser.i18n.getMessage(messageId, substitutions);
|
||||||
|
return message || messageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.linklogI18n = getLocalizedMessage;
|
||||||
|
|
||||||
|
document.querySelectorAll('[data-i18n]').forEach((element) => {
|
||||||
|
element.textContent = getLocalizedMessage(element.dataset.i18n);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('[data-i18n-placeholder]').forEach((element) => {
|
||||||
|
element.placeholder = getLocalizedMessage(element.dataset.i18nPlaceholder);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('[data-i18n-alt]').forEach((element) => {
|
||||||
|
element.alt = getLocalizedMessage(element.dataset.i18nAlt);
|
||||||
|
});
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "LinkLog",
|
"name": "__MSG_extensionName__",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Capture and submit page links to LinkLog.",
|
"description": "__MSG_extensionDescription__",
|
||||||
|
"default_locale": "en-US",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"activeTab",
|
"activeTab",
|
||||||
"storage",
|
"storage",
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
"<all_urls>"
|
"<all_urls>"
|
||||||
],
|
],
|
||||||
"action": {
|
"action": {
|
||||||
"default_title": "LinkLog",
|
"default_title": "__MSG_extensionName__",
|
||||||
"default_popup": "popup.html",
|
"default_popup": "popup.html",
|
||||||
"default_icon": {
|
"default_icon": {
|
||||||
"16": "icon-16.png",
|
"16": "icon-16.png",
|
||||||
|
|||||||
+21
-20
@@ -5,65 +5,66 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>LinkLog Settings</title>
|
<title data-i18n="settingsTitle">LinkLog Settings</title>
|
||||||
<link rel="stylesheet" href="options.css" />
|
<link rel="stylesheet" href="options.css" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<main class="options-shell">
|
<main class="options-shell">
|
||||||
<img class="extension-logo" src="logo.svg" alt="LinkLog" />
|
<img class="extension-logo" src="logo.svg" data-i18n-alt="extensionName" alt="LinkLog" />
|
||||||
<h1>Settings</h1>
|
<h1 data-i18n="settings">Settings</h1>
|
||||||
|
|
||||||
<div id="status" class="status hidden" aria-live="polite"></div>
|
<div id="status" class="status hidden" aria-live="polite"></div>
|
||||||
|
|
||||||
<section id="logged-in" class="logged-in hidden" aria-live="polite">
|
<section id="logged-in" class="logged-in hidden" aria-live="polite">
|
||||||
<p id="session-summary"></p>
|
<p id="session-summary"></p>
|
||||||
<button type="button" id="sign-out">Sign out</button>
|
<button type="button" id="sign-out" data-i18n="signOut">Sign out</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<form id="settings-form">
|
<form id="settings-form">
|
||||||
<label>
|
<label>
|
||||||
Backend URL
|
<span data-i18n="backendUrlLabel">Backend URL</span>
|
||||||
<input id="backend-url" type="url" placeholder="https://example.com" />
|
<input id="backend-url" type="url" placeholder="https://example.com" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
Username
|
<span data-i18n="usernameLabel">Username</span>
|
||||||
<input id="username" type="text" placeholder="alice" />
|
<input id="username" type="text" data-i18n-placeholder="usernamePlaceholder" placeholder="alice" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
Password
|
<span data-i18n="passwordLabel">Password</span>
|
||||||
<input id="password" type="password" />
|
<input id="password" type="password" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<button type="submit">Save and log in</button>
|
<button type="submit" data-i18n="saveAndLogIn">Save and log in</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<section class="about-plugin">
|
<section class="about-plugin">
|
||||||
<h2>This Plugin</h2>
|
<h2 data-i18n="thisPlugin">This Plugin</h2>
|
||||||
<p>This plugin will log links to a backend LinkLog server which will publish them on a website and potentially as
|
<p data-i18n="pluginDescription">This plugin will log links to a backend LinkLog server which will publish them on a website and potentially as
|
||||||
an entry
|
an entry
|
||||||
on a fediverse service or other locations, depending on the plugins configured.</p>
|
on a fediverse service or other locations, depending on the plugins configured.</p>
|
||||||
<p>Users of this plugin will need an account on a LinkLog server</p>
|
<p data-i18n="accountRequirement">Users of this plugin will need an account on a LinkLog server</p>
|
||||||
<h2>Privacy</h2>
|
<h2 data-i18n="privacy">Privacy</h2>
|
||||||
<p>This plugin respects your privacy and does not collect any personal data beyond what is necessary to log links
|
<p data-i18n="privacyDescription">This plugin respects your privacy and does not collect any personal data beyond what is necessary to log links
|
||||||
to your LinkLog server.</p>
|
to your LinkLog server.</p>
|
||||||
<p>The URL - after a best effort try to remove tracking parameters -, the title of the webpage, a possible
|
<p data-i18n="storedData">The URL - after a best effort try to remove tracking parameters -, the title of the webpage, a possible
|
||||||
comment, and a timestamp of visit will be stored on the backend server, and will be made public in combination
|
comment, and a timestamp of visit will be stored on the backend server, and will be made public in combination
|
||||||
with
|
with
|
||||||
the user's profile as registered on the backend server.
|
the user's profile as registered on the backend server.
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>LinkLog Backend</h2>
|
<h2 data-i18n="backendHeading">LinkLog Backend</h2>
|
||||||
<p>The backend URL is a selfhosted linklog application. See its <a
|
<p><span data-i18n="backendDescription">The backend URL is a selfhosted linklog application. See its</span> <a
|
||||||
href="https://git.kolkman.org/olaf/Link-Log">repository</a> for its source.</p>
|
href="https://git.kolkman.org/olaf/Link-Log" data-i18n="repository">repository</a> <span data-i18n="backendSource">for its source.</span></p>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<footer class="extension-footer">Copyright © 2026 Olaf Kolkman · <a
|
<footer class="extension-footer"><span data-i18n="copyright">Copyright © 2026 Olaf Kolkman</span> · <a
|
||||||
href="https://git.kolkman.org/olaf/Link-Log">Repository</a></footer>
|
href="https://git.kolkman.org/olaf/Link-Log" data-i18n="repository">Repository</a></footer>
|
||||||
|
|
||||||
|
<script src="l10n.js"></script>
|
||||||
<script src="options.js"></script>
|
<script src="options.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ const session = document.getElementById('logged-in');
|
|||||||
const sessionSummary = document.getElementById('session-summary');
|
const sessionSummary = document.getElementById('session-summary');
|
||||||
const signOutButton = document.getElementById('sign-out');
|
const signOutButton = document.getElementById('sign-out');
|
||||||
|
|
||||||
|
const t = window.linklogI18n;
|
||||||
|
|
||||||
function setStatus(message, isError = false) {
|
function setStatus(message, isError = false) {
|
||||||
statusEl.textContent = message;
|
statusEl.textContent = message;
|
||||||
statusEl.classList.remove('hidden');
|
statusEl.classList.remove('hidden');
|
||||||
@@ -43,7 +45,7 @@ async function loadSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showLoggedIn(username, backendUrl) {
|
function showLoggedIn(username, backendUrl) {
|
||||||
sessionSummary.textContent = `${username} logged in at ${backendUrl}`;
|
sessionSummary.textContent = t('loggedInAt', [username, backendUrl]);
|
||||||
session.classList.remove('hidden');
|
session.classList.remove('hidden');
|
||||||
form.classList.add('hidden');
|
form.classList.add('hidden');
|
||||||
}
|
}
|
||||||
@@ -64,7 +66,7 @@ async function saveSettingsAndLogin(event) {
|
|||||||
const password = passwordInput.value;
|
const password = passwordInput.value;
|
||||||
|
|
||||||
if (!backendUrl || !username || !password) {
|
if (!backendUrl || !username || !password) {
|
||||||
setStatus('Please fill in all fields', true);
|
setStatus(t('fillAllFields'), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +78,7 @@ async function saveSettingsAndLogin(event) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Login failed');
|
throw new Error(t('loginFailed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
@@ -91,9 +93,9 @@ async function saveSettingsAndLogin(event) {
|
|||||||
|
|
||||||
showLoggedIn(data.user?.username || username, backendUrl);
|
showLoggedIn(data.user?.username || username, backendUrl);
|
||||||
passwordInput.value = '';
|
passwordInput.value = '';
|
||||||
setStatus('Logged in successfully');
|
setStatus(t('loggedInSuccessfully'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatus('Unable to log in. Check backend URL and credentials.', true);
|
setStatus(t('unableToLogIn'), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +110,7 @@ async function signOut() {
|
|||||||
}
|
}
|
||||||
await clearSession();
|
await clearSession();
|
||||||
showLoggedOut();
|
showLoggedOut();
|
||||||
setStatus('Signed out');
|
setStatus(t('signedOut'));
|
||||||
}
|
}
|
||||||
|
|
||||||
form.addEventListener('submit', saveSettingsAndLogin);
|
form.addEventListener('submit', saveSettingsAndLogin);
|
||||||
|
|||||||
+14
-13
@@ -4,48 +4,49 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>LinkLog</title>
|
<title data-i18n="extensionName">LinkLog</title>
|
||||||
<link rel="stylesheet" href="popup.css" />
|
<link rel="stylesheet" href="popup.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main class="popup-shell">
|
<main class="popup-shell">
|
||||||
<header>
|
<header>
|
||||||
<img class="extension-logo" src="logo.svg" alt="LinkLog" />
|
<img class="extension-logo" src="logo.svg" data-i18n-alt="extensionName" alt="LinkLog" />
|
||||||
<a id="feed-link" class="feed-link hidden" href="/" target="_blank" rel="noopener noreferrer">LinkLog</a>
|
<a id="feed-link" class="feed-link hidden" href="/" target="_blank" rel="noopener noreferrer" data-i18n="extensionName">LinkLog</a>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div id="status" class="status hidden" aria-live="polite"></div>
|
<div id="status" class="status hidden" aria-live="polite"></div>
|
||||||
|
|
||||||
<form id="link-form">
|
<form id="link-form">
|
||||||
<label>
|
<label>
|
||||||
Title
|
<span data-i18n="titleLabel">Title</span>
|
||||||
<input id="title" name="title" type="text" />
|
<input id="title" name="title" type="text" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
URL
|
<span data-i18n="urlLabel">URL</span>
|
||||||
<input id="url" name="url" type="url" />
|
<input id="url" name="url" type="url" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
Comment
|
<span data-i18n="commentLabel">Comment</span>
|
||||||
<textarea id="comment" name="comment" rows="3" placeholder="Your comment"></textarea>
|
<textarea id="comment" name="comment" rows="3" data-i18n-placeholder="commentPlaceholder" placeholder="Your comment"></textarea>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Tags</legend>
|
<legend data-i18n="tagsLabel">Tags</legend>
|
||||||
<div id="existing-tags" class="tag-options">Loading tags...</div>
|
<div id="existing-tags" class="tag-options" data-i18n="loadingTags">Loading tags...</div>
|
||||||
<input id="new-tags" type="text" pattern="#[^, ]+(,\s*#[^, ]+)*" placeholder="#new-tag, #another-tag" />
|
<input id="new-tags" type="text" pattern="#[^, ]+(,\s*#[^, ]+)*" data-i18n-placeholder="newTagsPlaceholder" placeholder="#new-tag, #another-tag" />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button type="submit" id="submit-link">Save link</button>
|
<button type="submit" id="submit-link" data-i18n="saveLink">Save link</button>
|
||||||
<button type="button" id="open-settings" class="secondary">Settings</button>
|
<button type="button" id="open-settings" class="secondary" data-i18n="settings">Settings</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
<footer class="extension-footer">Copyright © 2026 Olaf Kolkman · <a href="https://git.kolkman.org/olaf/Link-Log">Repository</a></footer>
|
<footer class="extension-footer"><span data-i18n="copyright">Copyright © 2026 Olaf Kolkman</span> · <a href="https://git.kolkman.org/olaf/Link-Log" data-i18n="repository">Repository</a></footer>
|
||||||
|
|
||||||
|
<script src="l10n.js"></script>
|
||||||
<script src="popup.js"></script>
|
<script src="popup.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+10
-8
@@ -11,6 +11,8 @@ const existingTags = document.getElementById('existing-tags');
|
|||||||
const newTagsInput = document.getElementById('new-tags');
|
const newTagsInput = document.getElementById('new-tags');
|
||||||
const feedLink = document.getElementById('feed-link');
|
const feedLink = document.getElementById('feed-link');
|
||||||
|
|
||||||
|
const t = window.linklogI18n;
|
||||||
|
|
||||||
function setStatus(message, isError = false) {
|
function setStatus(message, isError = false) {
|
||||||
statusEl.textContent = message;
|
statusEl.textContent = message;
|
||||||
statusEl.classList.remove('hidden');
|
statusEl.classList.remove('hidden');
|
||||||
@@ -42,14 +44,14 @@ async function updateFeedLink() {
|
|||||||
async function loadExistingTags() {
|
async function loadExistingTags() {
|
||||||
const settings = await getSettings();
|
const settings = await getSettings();
|
||||||
if (!settings.backendUrl || !settings.accessToken) {
|
if (!settings.backendUrl || !settings.accessToken) {
|
||||||
existingTags.textContent = 'Sign in to select existing tags.';
|
existingTags.textContent = t('signInToSelectTags');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const response = await fetch(`${settings.backendUrl}/api/tags`, {
|
const response = await fetch(`${settings.backendUrl}/api/tags`, {
|
||||||
headers: {'Authorization': `Bearer ${settings.accessToken}`},
|
headers: {'Authorization': `Bearer ${settings.accessToken}`},
|
||||||
});
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
existingTags.textContent = 'Could not load existing tags.';
|
existingTags.textContent = t('loadTagsFailed');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tags = await response.json();
|
const tags = await response.json();
|
||||||
@@ -96,14 +98,14 @@ async function populateCurrentTab() {
|
|||||||
|
|
||||||
async function handleSubmit(event) {
|
async function handleSubmit(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setStatus('Submitting...', false);
|
setStatus(t('submitting'), false);
|
||||||
|
|
||||||
const settings = await getSettings();
|
const settings = await getSettings();
|
||||||
const token = settings.accessToken;
|
const token = settings.accessToken;
|
||||||
const backendUrl = settings.backendUrl;
|
const backendUrl = settings.backendUrl;
|
||||||
|
|
||||||
if (!token || !backendUrl) {
|
if (!token || !backendUrl) {
|
||||||
setStatus('Please configure the backend URL and log in first.', true);
|
setStatus(t('configureAndLogIn'), true);
|
||||||
browser.runtime.openOptionsPage();
|
browser.runtime.openOptionsPage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -125,18 +127,18 @@ async function handleSubmit(event) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
setStatus('Session expired. Re-authenticate in settings.', true);
|
setStatus(t('sessionExpired'), true);
|
||||||
browser.runtime.openOptionsPage();
|
browser.runtime.openOptionsPage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Submission failed');
|
throw new Error(t('submissionFailed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
setStatus('Link saved successfully');
|
setStatus(t('linkSaved'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatus('Submission failed. Check your backend connection.', true);
|
setStatus(t('submissionFailedConnection'), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user