camper/pkg/locale/locale.go

119 lines
2.5 KiB
Go
Raw Normal View History

Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
/*
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
* SPDX-License-Identifier: AGPL-3.0-only
*/
package locale
import (
"context"
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
"github.com/leonelquinteros/gotext"
"golang.org/x/text/language"
"dev.tandem.ws/tandem/camper/pkg/database"
)
type Locale struct {
*gotext.Locale
CurrencyPattern string
Language language.Tag
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
Endonym string
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
}
type Locales map[language.Tag]*Locale
func (m Locales) Tags() []language.Tag {
keys := make([]language.Tag, len(m))
i := 0
for k := range m {
keys[i] = k
i++
}
return keys
}
func GetAll(ctx context.Context, db *database.DB) (Locales, error) {
availableLanguages, err := getAvailableLanguages(ctx, db)
if err != nil {
return nil, err
}
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
locales := Locales{}
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
for _, lang := range availableLanguages {
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
locale := lang.locale()
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
locale.AddDomain("camper")
locales[lang.tag] = locale
}
return locales, nil
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
}
func (l *Locale) Gettext(str string) string {
return l.GetD(l.GetDomain(), str)
}
func (l *Locale) Pgettext(str string, ctx string) string {
return l.GetDC(l.GetDomain(), str, ctx)
}
func (l *Locale) GettextNoop(str string) string {
return str
}
func Match(acceptLanguage string, locales Locales, matcher language.Matcher) *Locale {
t, _, err := language.ParseAcceptLanguage(acceptLanguage)
if err != nil {
return nil
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
}
var locale *Locale
tag, _, confidence := matcher.Match(t...)
if confidence > language.No {
var ok bool
locale, ok = locales[tag]
for !ok && !tag.IsRoot() {
tag = tag.Parent()
locale, ok = locales[tag]
}
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
}
return locale
}
type availableLanguage struct {
tag language.Tag
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
endonym string
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
currencyPattern string
}
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
func getAvailableLanguages(ctx context.Context, db *database.DB) ([]*availableLanguage, error) {
rows, err := db.Query(ctx, "select lang_tag, endonym, currency_pattern from language where selectable")
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
if err != nil {
return nil, err
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
}
defer rows.Close()
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
var languages []*availableLanguage
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
for rows.Next() {
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
lang := &availableLanguage{}
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
var langTag string
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
err = rows.Scan(&langTag, &lang.endonym, &lang.currencyPattern)
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
if err != nil {
return nil, err
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
}
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
lang.tag = language.MustParse(langTag)
languages = append(languages, lang)
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
}
if rows.Err() != nil {
return nil, rows.Err()
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
}
return languages, nil
Add the skeleton of the web application It does nothing more than to server a single page that does nothing interesting. This time i do not use a router. Instead, i am trying out a technique i have seen in an article[0] that i have tried in other, smaller, projects and seems to work surprisingly well: it just “cuts off” the URI path by path, passing the request from handler to handler until it finds its way to a handler that actually serves the request. That helps to loosen the coupling between the application and lower handlers, and makes dependencies explicit, because i need to pass the locale, company, etc. down instead of storing them in contexts. Let’s see if i do not regret it on a later date. I also made a lot more packages that in Numerus. In Numerus i actually only have the single pkg package, and it works, kind of, but i notice how i name my methods to avoid clashing instead of using packages for that. That is, instead of pkg.NewApp i now have app.New. Initially i thought that Locale should be inside app, but then there was a circular dependency between app and template. That is why i created a separate package, but now i am wondering if template should be inside app too, but then i would have app.MustRenderTemplate instead of template.MustRender. The CSS is the most bare-bones file i could write because i am focusing in markup right now; Oriol will fill in the file once the application is working. [0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
}
Add the language switched to the public layout The language switcher needs the same information as languageLinks needed, namely the list of locales and the current Path, to construct the URI to all alternate versions. However, in this case i need access to this data in the template context, to build the list of links. At first i use request’s context to hold the list of available locales from application, and it worked, possibly without ill-effects, but i realized that i was doing it just to avoid a new parameter. Or, more precise, an _explicit_ parameter; the context was used to skip the inner functions between app and template.MustRenderPublic, but the parameter was there all the same. Finally, i thought that some handler might want to filter the list of locales to show only the ones that it has a translation of. In that case, i would need to extract the locales from the context, filter it, and create a new request with the updated context. That made little sense, and made me add the explicit locales parameter. Since now the template has the same data as languageLinks, there is little point of having the link in the HTTP response headers, and added the <link> elements to <head>. I thought that maybe i could avoid these <links> as they give the exact same data as the language switch, but Google says nothing of using regular anchors to gather information about localized versions of the document[0], thus i opted to be conservative. One can reason that the <head> has more weight for Google, as most sites with user-generated content, which could contain these anchors, rarely allow users to edit the <head>. [0]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-06 03:53:52 +00:00
func (lang *availableLanguage) locale() *Locale {
return &Locale{
gotext.NewLocale("locale", lang.tag.String()),
lang.currencyPattern,
lang.tag,
lang.endonym,
}
}