wantedly / hi18n

message internationalization meets immutability and type-safety

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Feature Request] Methods to reduce template codes

lightsound opened this issue · comments

Premise

I think there are two concepts in translation books: global and local.

It is very difficult to manage all translations in global. This is because it is difficult to find the target translation ID from a huge book, and it is also difficult to define translation IDs so that they are not covered by each other.

So I think we should have local books, and they should be located by component.

Why (Problem)

Given the above premise, we need to create a local book for each component. But now, that would be too much template code. Below is an example code. It is a bit difficult to write this for each component.

import type { Message } from "@hi18n/core";
import { Book, Catalog, msg } from "@hi18n/core";
import { useI18n } from "@hi18n/react";

type Vocabulary = {
  greet: Message;
};

const catalogEn = new Catalog<Vocabulary>({
  greet: msg("Hello"),
});

const catalogJa = new Catalog<Vocabulary>({
  greet: msg("こんにちは"),
});

const book = new Book<Vocabulary>({
  en: catalogEn,
  ja: catalogJa,
});

What

I would like a method to reduce the template code. For example, the code might be as follows.

type Locale = "ja" | "en";

const createBook = <Vocabulary extends VocabularyBase>(catalogs: {
  [K in Locale]: Vocabulary;
}) => {
  const book: { [K in Locale]: Catalog<Vocabulary> } = {
    ja: new Catalog<Vocabulary>(catalogs.ja),
    en: new Catalog<Vocabulary>(catalogs.en),
  };
  return new Book<Vocabulary>(book);
};

Usage.

const book = createBook<{ greet: Message }>({
  en: { greet: msg("Hello") }, // I would also like to omit `msg`.
  ja: { greet: msg("こんにちは") },
});

const Component = () => {
  const { t } = useI18n(book);
  return <h1>{t("greet")}</h1>
}

Currently, such methods cannot be used because the sync command does not work. So, It will need to be radically changed.🥲

These are my suggestions. I hope this will be helpful.

it is difficult to find the target translation ID from a huge book

This is merely a tooling problem. @hi18n/ts-plugin may implement such functionality, or rather you may request TypeScript itself to handle such constructs. At least there is already a case where you can navigate through a string literal just like an identifier (e.g. clicking on a property key).

and it is also difficult to define translation IDs so that they are not covered by each other.

Do you mean to not overlap each other? The simplest solution is to prefix translation ids based on file/directory structure.

Book splitting is one of the important features of hi18n, but translation namespacing is not an intended use-case of it.

So I think we should have local books, and they should be located by component.

Book-per-component sounds too fine-grained and it is likely not hi18n's scope.

// I would also like to omit `msg`.

This is almost inevitable due to the nature of string literal types of TypeScript. You should ask TypeScript about it but I think it is not likely improved.

The following interface is possible because in this form, the catalogs are easily located:

export default new Book<Vocabulary>({
  en: {
    "example/greeting": msg("..."),
  },
  ja: {
    "example/greeting": msg("..."),
  },
});

Though it comes with the cost of the CLI's complexity. As the intended use case is not in hi18n's scope, there is no reason to implement it now.

Do you mean to not overlap each other?

Yes!

The simplest solution is to prefix translation ids based on file/directory structure.
Book splitting is one of the important features of hi18n, but translation namespacing is not an intended use-case of it.

I don't know the advantage of that approach (naming based on file/directory on a global book) over the book-per-component approach. I thought book-per-component would be easier to manage than that.

Book-per-component sounds too fine-grained and it is likely not hi18n's scope.

Looking at the recent updates to React, the idea of colocation seems to be gaining strength. I'm not even sure if colocation is suitable for i18n as well. However, when I translated with a book-per-component approach using hi18n, it worked very well. Performance may have been sacrificed, but it was more manageable (in this case, performance optimization for the book-per-component approach may be necessary).

I'm not going to say that book-per-component is the best approach. It is just an opinion that I think hi18n could possibly be better.

Without a doubt, hi18n is already great and I will continue to use it.😆

Closing as wontfix. Thank you for the feedback anyway.