@autobusal/providers 1.14.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/Setup/Setup.tsx +1 -1
- package/Setup/languages.ts +31 -6
- package/package.json +1 -1
- package/types/locations.ts +16 -6
- package/types/settings.ts +17 -13
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,32 @@ adheres to [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
|
7
7
|
> Note: 1.8.0 through 1.11.0 were published without changelog entries. The
|
|
8
8
|
> gap is left as-is rather than reconstructed after the fact.
|
|
9
9
|
|
|
10
|
+
## [1.16.0] - 2026-08-02
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **SEO overrides are per language.** `LabelSettings.seo` and the location
|
|
15
|
+
types carry a `{locale: {title, description}}` map. The label's homepage
|
|
16
|
+
override is sent WHOLE and picked client-side, unlike the country/city
|
|
17
|
+
ones which resolve server-side - not an inconsistency but a bootstrap fact:
|
|
18
|
+
`/api/settings/get` is the one request that runs before i18n exists, so the
|
|
19
|
+
server cannot know which language to answer in. Resolving it there put
|
|
20
|
+
English copy on the Italian homepage.
|
|
21
|
+
- **`seo_keywords` is gone** everywhere. Google has ignored the meta keywords
|
|
22
|
+
tag since 2009; the field could only ever cost somebody an afternoon.
|
|
23
|
+
|
|
24
|
+
## [1.15.0] - 2026-08-02
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **The URL decides the language.** `getLanguage()` now reads a locale prefix
|
|
29
|
+
off the path before falling back to the stored preference and then the
|
|
30
|
+
brand default, and takes the brand's `available` list so an unrecognised
|
|
31
|
+
first segment (`/city/tirana`) is never mistaken for a language. This is
|
|
32
|
+
the point of localised URLs: a link has to decide what its recipient sees,
|
|
33
|
+
so someone whose last visit was in Albanian still gets Italian from a
|
|
34
|
+
shared `/it/...` link. Unprefixed URLs are unaffected.
|
|
35
|
+
|
|
10
36
|
## [1.14.0] - 2026-08-02
|
|
11
37
|
|
|
12
38
|
### Changed
|
package/Setup/Setup.tsx
CHANGED
|
@@ -15,7 +15,7 @@ const Setup = ({ type, children }: Props): JSX.Element => {
|
|
|
15
15
|
useGetMenu();
|
|
16
16
|
useUserBootstrap();
|
|
17
17
|
|
|
18
|
-
languages(type, data.preferences.languages.default);
|
|
18
|
+
languages(type, data.preferences.languages.default, data.preferences.languages.available);
|
|
19
19
|
|
|
20
20
|
// Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
21
21
|
// The brand's GTM container, from labels_settings via the admin GUI.
|
package/Setup/languages.ts
CHANGED
|
@@ -2,9 +2,34 @@ import i18next from 'i18next';
|
|
|
2
2
|
import Backend from 'i18next-http-backend';
|
|
3
3
|
import { initReactI18next } from 'react-i18next';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The language to start in.
|
|
7
|
+
*
|
|
8
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-02
|
|
9
|
+
* A locale-prefixed URL now wins over the stored preference. That ordering
|
|
10
|
+
* is the whole point of localised URLs: a link has to decide what its
|
|
11
|
+
* recipient sees, so somebody whose last visit was in Albanian must still
|
|
12
|
+
* get Italian when they open a shared /it/... link. The stored preference
|
|
13
|
+
* still covers every unprefixed URL - the homepage a returning visitor
|
|
14
|
+
* types in, and the whole account area, which is not localised.
|
|
15
|
+
*
|
|
16
|
+
* `available` is passed in rather than read from anywhere global so this
|
|
17
|
+
* stays a pure function of its inputs, and so an unrecognised first segment
|
|
18
|
+
* (/city/tirana) is never mistaken for a language.
|
|
19
|
+
*/
|
|
20
|
+
export const getLanguage = (defaultLanguage: string, available: string[] = []): string => {
|
|
21
|
+
const [ , first ] = window.location.pathname.split('/');
|
|
22
|
+
|
|
23
|
+
if (first && available.includes(first)) {
|
|
24
|
+
return first;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const stored = localStorage.getItem('language');
|
|
28
|
+
|
|
29
|
+
return (stored && (available.length === 0 || available.includes(stored)))
|
|
30
|
+
? stored
|
|
31
|
+
: defaultLanguage;
|
|
32
|
+
};
|
|
8
33
|
|
|
9
34
|
// Cache-busting query param for the language files. `Cache-Control: no-cache`
|
|
10
35
|
// on the obtapi side only asks caches to revalidate before reuse - in
|
|
@@ -18,7 +43,7 @@ export const getLanguage = (defaultLanguage: string): string => (
|
|
|
18
43
|
// consumer that hasn't set VITE_BUILD_ID yet (no worse than before).
|
|
19
44
|
const buildId = import.meta.env.VITE_BUILD_ID ?? 'dev';
|
|
20
45
|
|
|
21
|
-
const languages = (type: string, defaultLanguage: string): void => {
|
|
46
|
+
const languages = (type: string, defaultLanguage: string, available: string[] = []): void => {
|
|
22
47
|
if (i18next.isInitialized) {
|
|
23
48
|
return;
|
|
24
49
|
}
|
|
@@ -30,7 +55,7 @@ const languages = (type: string, defaultLanguage: string): void => {
|
|
|
30
55
|
interpolation: {
|
|
31
56
|
escapeValue: false
|
|
32
57
|
},
|
|
33
|
-
lng: getLanguage(defaultLanguage),
|
|
58
|
+
lng: getLanguage(defaultLanguage, available),
|
|
34
59
|
fallbackLng: defaultLanguage,
|
|
35
60
|
debug: import.meta.env.DEV,
|
|
36
61
|
backend: {
|
|
@@ -45,7 +70,7 @@ const languages = (type: string, defaultLanguage: string): void => {
|
|
|
45
70
|
// immediately (don't wait for the async backend fetch) and keep it in sync
|
|
46
71
|
// on every future change, whether triggered by ChangeLanguage or anything
|
|
47
72
|
// else that calls i18next.changeLanguage().
|
|
48
|
-
document.documentElement.lang = getLanguage(defaultLanguage);
|
|
73
|
+
document.documentElement.lang = getLanguage(defaultLanguage, available);
|
|
49
74
|
i18next.on('languageChanged', (lng) => {
|
|
50
75
|
document.documentElement.lang = lng;
|
|
51
76
|
});
|
package/package.json
CHANGED
package/types/locations.ts
CHANGED
|
@@ -30,9 +30,14 @@ export interface CountryData {
|
|
|
30
30
|
// Optional hand-written override for the public country page's title/
|
|
31
31
|
// description/keywords - see LocationCountry.tsx for the fallback-to-
|
|
32
32
|
// template logic when these are unset.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
// Edited: Ferjolt Ozuni - Date: 2026-08-02
|
|
34
|
+
// Resolved to the request's language server-side on the PUBLIC read,
|
|
35
|
+
// so these stay flat there; `seo` is the raw per-locale map the admin
|
|
36
|
+
// form reads and writes. `seo_keywords` is gone - Google has ignored
|
|
37
|
+
// the meta keywords tag since 2009.
|
|
38
|
+
seo_title?: string | null
|
|
39
|
+
seo_description?: string | null
|
|
40
|
+
seo?: Record<string, { title?: string, description?: string }>
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
export interface CityStats {
|
|
@@ -74,9 +79,14 @@ export interface CityData {
|
|
|
74
79
|
// Optional hand-written override for the public city page's title/
|
|
75
80
|
// description/keywords - see LocationCity.tsx for the fallback-to-
|
|
76
81
|
// template logic when these are unset.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
// Edited: Ferjolt Ozuni - Date: 2026-08-02
|
|
83
|
+
// Resolved to the request's language server-side on the PUBLIC read,
|
|
84
|
+
// so these stay flat there; `seo` is the raw per-locale map the admin
|
|
85
|
+
// form reads and writes. `seo_keywords` is gone - Google has ignored
|
|
86
|
+
// the meta keywords tag since 2009.
|
|
87
|
+
seo_title?: string | null
|
|
88
|
+
seo_description?: string | null
|
|
89
|
+
seo?: Record<string, { title?: string, description?: string }>
|
|
80
90
|
}
|
|
81
91
|
|
|
82
92
|
export interface StopData {
|
package/types/settings.ts
CHANGED
|
@@ -37,14 +37,18 @@ export interface SettingsData {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
// Edited: Ferjolt Ozuni - Date: 2026-07-31
|
|
40
|
-
// Optional admin-managed override for the homepage's title/description
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
// Optional admin-managed override for the homepage's title/description
|
|
41
|
+
// (Labels\AdminController::seo()) - StaticHome.tsx prefers these over its
|
|
42
|
+
// i18n translation-template values when set.
|
|
43
|
+
//
|
|
44
|
+
// Edited: Ferjolt Ozuni - Date: 2026-08-02
|
|
45
|
+
// The WHOLE per-language map, picked client-side by StaticHome - unlike
|
|
46
|
+
// the country/city overrides, which resolve server-side. This one request
|
|
47
|
+
// runs before i18n exists (Setup initialises i18n from the settings it is
|
|
48
|
+
// waiting on), so the server cannot know which language to answer in.
|
|
49
|
+
// A language with no entry has no override and keeps its own template.
|
|
50
|
+
// `keywords` is gone: Google has ignored the meta keywords tag since 2009.
|
|
51
|
+
seo?: Record<string, { title?: string, description?: string }>
|
|
48
52
|
|
|
49
53
|
preferences: {
|
|
50
54
|
company: string
|
|
@@ -226,11 +230,11 @@ export interface LabelSettings {
|
|
|
226
230
|
// Edited: Ferjolt Ozuni - Date: 2026-07-31
|
|
227
231
|
// Admin-managed homepage SEO override (public seo? above is populated
|
|
228
232
|
// from this) - see Labels\AdminController::seo().
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
233
|
+
//
|
|
234
|
+
// Edited: Ferjolt Ozuni - Date: 2026-08-02
|
|
235
|
+
// Keyed by locale. A language with no entry has no override at all, which
|
|
236
|
+
// is what returns that language's homepage to its own template.
|
|
237
|
+
seo?: Record<string, { title?: string, description?: string }>
|
|
234
238
|
|
|
235
239
|
// Edited: Ferjolt Ozuni - Date: 2026-08-01
|
|
236
240
|
// Admin-managed Google Tag Manager container. The PUBLIC settings payload
|