Skip to content

本地化(国际化)

VueToCounter 提供了本地化功能,用于处理数字和时间间隔的本地化。

VueToCounterNumberVueToCounterDatetimeDuration 组件支持本地化,你可以通过 locale 属性来设置本地化的配置。

大多数情况下,你只需要将 locale 属性设置为 语言代码(如 enen-USzhzh-CN)即可。 VueToCounter 内部将调用 Intl API 来处理本地化。

时间间隔本地化

CodeSandbox Logo


~

点击查看代码
vue
<script setup>
import { ref } from "vue";
import LocaleSelect from "./LocaleSelect.vue";

const from = ref("2024-12-01T00:00:00");
const to = ref("2024-12-31T00:00:00");

function switchDatetime() {
  [from.value, to.value] = [to.value, from.value];
}

const locale = ref(navigator.language);
</script>

<template>
  <div class="text-center">
    <vue-to-counter-datetime-duration :value="[from, to]" :locale="locale" />
  </div>
  <hr />
  <div class="flex gap-4">
    <div>
      <input
        class="border border-solid p-1"
        v-model="from"
        type="datetime-local"
      />
      ~
      <input
        class="border border-solid p-1"
        v-model="to"
        type="datetime-local"
      />
    </div>
    <button class="border border-solid p-1" @click="switchDatetime">
      切换
    </button>
    <span class="flex-auto" />
    <locale-select
      class="border border-solid p-1 appearance-auto"
      v-model="locale"
    />
  </div>
</template>

<style scoped></style>
vue
<script setup>
const value = defineModel("modelValue");
</script>

<template>
  <select class="border border-solid p-1 appearance-auto" v-model="value">
    <optgroup label="中文">
      <option value="zh-CN">zh-CN</option>
      <option value="zh-HK">zh-HK</option>
      <option value="zh-TW">zh-TW</option>
    </optgroup>
    <optgroup label="English">
      <option value="en-US">en-US</option>
      <option value="en-GB">en-GB</option>
    </optgroup>
    <option value="ja-JP">ja-JP</option>
    <option value="ko-KR">ko-KR</option>
    <option value="de-DE">de-DE</option>
    <option value="fr-FR">fr-FR</option>
  </select>
</template>

<style scoped></style>
vue
<script setup>
import StackblitzLogo from "../assets/stackblitz-logo.svg";
import { ref, toRefs } from "vue";
import { getCodeStackblitzParams } from "./generate-stackblitz-params";
import sdk from "@stackblitz/sdk";
import packageInfo from "../../vue-to-counter/package.json";

const props = defineProps({
  title: {
    type: String,
    required: true,
  },
});
const { title } = toRefs(props);

const containerRef = ref();

function handleStackblitz() {
  if (!containerRef.value) return;

  const tabs = containerRef.value.querySelectorAll(".tabs > label");
  const blocks = containerRef.value.querySelectorAll(".blocks > div code");
  if (tabs.length !== blocks.length) {
    window.alert("The number of tabs and code blocks should be the same.");
    return;
  }

  const files = Array.from(tabs).map((tab, index) => ({
    filename: tab.textContent.trim(),
    content: blocks[index].textContent,
  }));

  const params = getCodeStackblitzParams(files, {
    title: `${title.value} - vue-to-counter@${packageInfo.version}`,
  });
  sdk.openProject(params, {
    openFile: "src/demo.vue",
  });
}
</script>

<template>
  <div ref="containerRef" class="demo-container">
    <div class="flex relative">
      <span class="flex-auto" />
      <span
        title="Open In Stackblitz"
        class="inline-block p-1 cursor-pointer hover:outline hover:outline-[#1389FD] outline-1"
        @click="handleStackblitz"
      >
        <img
          class="h-4 w-4 pointer-events-none"
          :src="StackblitzLogo"
          alt="CodeSandbox Logo"
        />
      </span>
    </div>
    <hr />
    <slot />
  </div>
</template>

<style lang="scss">
.demo-container {
  @apply flex flex-col justify-center border p-4 rounded-lg mt-4 text-sm;

  .vue-to-counter {
    @apply font-mono text-4xl;
  }

  .custom-block {
    @apply m-0;
  }
}
</style>

数字本地化

特别的,VueToCounterNumber 组件还需要设置 locale-number 属性。

CodeSandbox Logo

0110110440,,055011044


点击查看代码
vue
<script setup>
import { ref } from "vue";
import LocaleSelect from "./LocaleSelect.vue";

const number = ref(114514);

function switchNumber() {
  number.value = Math.floor(Math.random() * 1000000);
}

const locale = ref(navigator.language);
</script>

<template>
  <div class="text-center">
    <vue-to-counter-number :value="number" :locale="locale" locale-number />
  </div>
  <hr />
  <div class="flex gap-4">
    <input class="border border-solid p-1" v-model="number" type="number" />
    <button class="border border-solid p-1" @click="switchNumber">切换</button>
    <span class="flex-auto" />
    <locale-select
      class="border border-solid p-1 appearance-auto"
      v-model="locale"
    />
  </div>
</template>

<style scoped></style>
vue
<script setup>
const value = defineModel("modelValue");
</script>

<template>
  <select class="border border-solid p-1 appearance-auto" v-model="value">
    <optgroup label="中文">
      <option value="zh-CN">zh-CN</option>
      <option value="zh-HK">zh-HK</option>
      <option value="zh-TW">zh-TW</option>
    </optgroup>
    <optgroup label="English">
      <option value="en-US">en-US</option>
      <option value="en-GB">en-GB</option>
    </optgroup>
    <option value="ja-JP">ja-JP</option>
    <option value="ko-KR">ko-KR</option>
    <option value="de-DE">de-DE</option>
    <option value="fr-FR">fr-FR</option>
  </select>
</template>

<style scoped></style>
vue
<script setup>
import StackblitzLogo from "../assets/stackblitz-logo.svg";
import { ref, toRefs } from "vue";
import { getCodeStackblitzParams } from "./generate-stackblitz-params";
import sdk from "@stackblitz/sdk";
import packageInfo from "../../vue-to-counter/package.json";

const props = defineProps({
  title: {
    type: String,
    required: true,
  },
});
const { title } = toRefs(props);

const containerRef = ref();

function handleStackblitz() {
  if (!containerRef.value) return;

  const tabs = containerRef.value.querySelectorAll(".tabs > label");
  const blocks = containerRef.value.querySelectorAll(".blocks > div code");
  if (tabs.length !== blocks.length) {
    window.alert("The number of tabs and code blocks should be the same.");
    return;
  }

  const files = Array.from(tabs).map((tab, index) => ({
    filename: tab.textContent.trim(),
    content: blocks[index].textContent,
  }));

  const params = getCodeStackblitzParams(files, {
    title: `${title.value} - vue-to-counter@${packageInfo.version}`,
  });
  sdk.openProject(params, {
    openFile: "src/demo.vue",
  });
}
</script>

<template>
  <div ref="containerRef" class="demo-container">
    <div class="flex relative">
      <span class="flex-auto" />
      <span
        title="Open In Stackblitz"
        class="inline-block p-1 cursor-pointer hover:outline hover:outline-[#1389FD] outline-1"
        @click="handleStackblitz"
      >
        <img
          class="h-4 w-4 pointer-events-none"
          :src="StackblitzLogo"
          alt="CodeSandbox Logo"
        />
      </span>
    </div>
    <hr />
    <slot />
  </div>
</template>

<style lang="scss">
.demo-container {
  @apply flex flex-col justify-center border p-4 rounded-lg mt-4 text-sm;

  .vue-to-counter {
    @apply font-mono text-4xl;
  }

  .custom-block {
    @apply m-0;
  }
}
</style>